首页
社区
课程
招聘
[原创].NET的EXE启动流程跟踪(流水账)
发表于: 2012-12-19 12:13 11105

[原创].NET的EXE启动流程跟踪(流水账)

2012-12-19 12:13
11105

无聊写的东西罢了,流水账一样的玩意,使用的是.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。就这样了,下午还得上课撸撸睡了。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 6
支持
分享
最新回复 (6)
雪    币: 292
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
想研究这个,首先要有微软的调试符号,建议用windbg
2012-12-19 13:04
0
雪    币: 107
活跃值: (404)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3

StrongOD不是也能加载PDB么..把WINDBG下面那几个符号文件相关的文件拷贝到OD目录即可
2012-12-19 22:38
0
雪    币: 3149
活跃值: (66)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
od调试.net程序?学习了
2012-12-20 13:19
0
雪    币: 358
活跃值: (146)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
山野?学习了,看不懂……路过
2012-12-20 15:04
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
那如何通过c++程序启动.net的exe呢
2013-11-18 17:15
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
请问如何自己写一个c++的程序然后在内存中启动.net 的exe,为了不让人看到我.net的可执行文件,如果拿到.net的exe就被反编译了
2013-11-18 17:21
0
游客
登录 | 注册 方可回帖
返回
//