NET的EXE启动流程跟踪(流水账)

无聊写的东西罢了,流水账一样的玩意,使用的是.NET Framework 4.0。

在OD选项中设置中断于系统断点,因为.NET程序一启动,加载mscoree后,mscoree立马执行CorExeMain,是不返回的,所以.NET的EXE文件的EP是永远不会被执行的,关键的东西全在CorExeMain中,所以我们需要在mscoree的任何代码都没执行的时候断下来。
在模块中找到mscoree,在CorExeMain上F2,然后F9运行。
断了,CorExeMain的第一个call一开始我以为是登记SEH,可转身想想,这完全没必要,应该是一个有用的call,所以跟进去了。
跟进去后发现果然不是等级SEH的,继续看,显然这里面的第一个call也不可能是登记SEH的,跟进去,有一个运行时是否加载了的全局变量,现在是NULL,准备加载运行时。
下面有各种登记SEH的call,略过,一路F7,走到从注册表查询运行时,
在进行各种跑飞后,第一个访问的注册表是:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\Policy\,打开后调用RegQueryInfoKeyW,然后是RegEnumKeyExW,然后调用一个call,传入当前exe的版本,如“v4.0”,不断Enum是否当前已经有安装这个版本(就是注册表已经登记),找到这个Key的话,调用RegOpenKeyExW,取得里面的子版本路径,如“30319-30319”,也就是“v4.0.30319”,获取这个完全版本后,调用一个call,传入“mscoreei.dll”和“v4.0.30319”,call内会打开“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework”,取得字符串值“InstallRoot”,这个一般指向“C:\Windows\Microsoft.NET\Framework\”,然后“C:\Windows\Microsoft.NET\Framework\”+“v4.0.30319”,生成这个目录下面有一个mscoreei,会被载入,这个就是当前.NET运行时的核心库,mscoree到现在任务完成了,保存mscoreei的hModule,调用mscoree的函数的时候,GetProcAddress然后jmp到mscoreei就行了。

上面扯飞了,载入mscoreei后,首先GetProcAddress“RegisterShimImplCallback”和“RegisterShimImplCleanupCallback”这2个东西,然后是“SetShellShimInstance”,如果3个有一个取得失败,FreeLibrary,gameover。
再取得“OnShimDllMainCalled”,然后调用RegisterShimImplCallback,2个参数,2个都是callback,然后会GetProcAddress“_CorExeMain_RetAddr”、“_CorExeMain”、最终调用mscoreei的“_CorExeMain”,无返回。

mscoreei的ExeMain会进行这样一个调用:
/*6A82F576*/  PUSH EAX
/*6A82F577*/  INC EDX
/*6A82F578*/  MOV ECX,mscoreei.6A8264D0
/*6A82F57D*/  MOV DWORD PTR SS:[ESP+14],EDI
/*6A82F581*/  CALL mscoreei.6A82F412
/*6A82F586*/  MOV ESI,EAX
/*6A82F588*/  TEST ESI,ESI
/*6A82F58A*/  JS SHORT mscoreei.6A82F5A5
/*6A82F58C*/  CMP DWORD PTR SS:[ESP+10],EDI
/*6A82F590*/  JE SHORT mscoreei.6A82F5A5
/*6A82F592*/  CALL mscoreei.6A8257E8
/*6A82F597*/  TEST AL,AL
/*6A82F599*/  JNZ mscoreei.6A830642
/*6A82F59F*/  CALL DWORD PTR SS:[ESP+10] -> clr._CorExeMain
/*6A82F5A3*/  MOV ESI,EAX
/*6A82F5A5*/  PUSH ESI
/*6A82F5A6*/  CALL DWORD PTR DS:[<&KERNEL32.ExitProcess>]
/*6A82F5AC*/  INT3

6A82F412这个call会调用mscoreei.CreateInterface,传入2个GUID,返回一个ppv,调用ppv中的2个interface加载clr.dll等等东西后,就Release了。
然后就到CALL DWORD PTR SS:[ESP+10]这个clr的ExeMain了。

clr那货的ExeMain是:
/*651A414E*/  PUSH 14
/*651A4150*/  PUSH clr.651A4180
/*651A4155*/  CALL clr.65051050
/*651A415A*/  XOR EAX,EAX
/*651A415C*/  MOV DWORD PTR SS:[EBP-20],EAX
/*651A415F*/  MOV DWORD PTR SS:[EBP-1C],EAX
/*651A4162*/  MOV DWORD PTR SS:[EBP-4],EAX
/*651A4165*/  CALL clr.651A1ED8
/*651A416A*/  MOV DWORD PTR SS:[EBP-4],-2
/*651A4171*/  XOR EAX,EAX
/*651A4173*/  CALL clr.65051095
/*651A4178*/  RETN
显然忽略2个SEH东东,就是clr.651A1ED8这个玩意了。

跟进去,上截图吧,相信大家不陌生:

下面有一段这样的代码:
/*651A1F67*/  MOV BYTE PTR SS:[EBP-4],4
/*651A1F6B*/  PUSH 0
/*651A1F6D*/  CALL DWORD PTR DS:[<&KERNEL32.GetModuleHandleW>]
/*651A1F73*/  MOV ECX,EAX
/*651A1F75*/  CALL clr.651A1E1E
那个call就是我们.NET程序的真正EP了,程序结束之前这个call都不会返回。返回了就进行一些扫尾工作,进程end~

进去后,是这样的:
/*651A1E1E*/  PUSH 34
/*651A1E20*/  PUSH clr.651A1EB0
/*651A1E25*/  CALL clr.65051050
/*651A1E2A*/  MOV EDI,ECX
/*651A1E2C*/  TEST EDI,EDI
/*651A1E2E*/  JE clr.6522C364
/*651A1E34*/  PUSH ECX
/*651A1E35*/  PUSH ECX
/*651A1E36*/  MOV ECX,clr.651A1EA0
/*651A1E3B*/  CALL clr.65060F11
/*651A1E40*/  MOV DWORD PTR SS:[EBP-28],EDI
/*651A1E43*/  AND DWORD PTR SS:[EBP-20],0
/*651A1E47*/  AND DWORD PTR SS:[EBP-4],0
/*651A1E4B*/  CALL clr.65051CB8
/*651A1E50*/  PUSH EAX
/*651A1E51*/  LEA ECX,DWORD PTR SS:[EBP-44]
/*651A1E54*/  CALL clr.6505116A
/*651A1E59*/  MOV DWORD PTR SS:[EBP-4],1
/*651A1E60*/  MOV ECX,EDI
/*651A1E62*/  CALL clr.651A183B
/*651A1E67*/  AND DWORD PTR SS:[EBP-4],0
/*651A1E6B*/  CALL clr.651C4EE1
/*651A1E70*/  MOV DWORD PTR SS:[EBP-4],-2
/*651A1E77*/  PUSH ECX
/*651A1E78*/  PUSH ECX
/*651A1E79*/  MOV ECX,clr.651A1E90
/*651A1E7E*/  CALL clr.65060F11
/*651A1E83*/  XOR EAX,EAX
/*651A1E85*/  INC EAX
/*651A1E86*/  CALL clr.65051095
/*651A1E8B*/  RETN
关键的call是CALL 651A183B,其他的都是SEH和扫屁股的,跟进去。
F7,好长的call...算了,闭着眼睛Ctrl+F8。。。
停在这里:
  PUSH 0
  CALL clr.65117550
进去
  PUSH EBX
  LEA EAX,DWORD PTR SS:[ESP+18]
  PUSH EAX
  MOV ECX,EDI
  CALL clr.65117DDE
跑了那么多,累死了。。。
其实跑到65117DDE的时候,整个进程还是“干净”的,也就是.NET的模块都没载入,仅仅载入了当前的mscoreei和资源ui的dll而已。。。
继续Ctrl+F8。。。
  PUSH EAX
  LEA ECX,DWORD PTR SS:[EBP-110]
  CALL clr.65062DA1
跑到65062DA1的时候我在stack的参数里面发现了老子编译的工程Release文件夹路径。。。狗血。。。
65062DA1这个call上上下下执行了N次,加载了程序使用的.NET的dll文件,然后进入JIT执行,没管了,想的跟可以下断clr.CreateApplicationContext。就这样了,下午还得上课撸撸睡了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值