首页
社区
课程
招聘
[旧帖] [讨论]如果获取main()函数的地址? 0.00雪花
发表于: 2008-9-23 15:29 5523

[旧帖] [讨论]如果获取main()函数的地址? 0.00雪花

2008-9-23 15:29
5523
目前先只考虑VC编译器系列的。目前我的想法是这样的,从CRT0.C 里的启动函数入手,寻找特征。我在坛子了看到过一篇文章:库函数的快速鉴别和识别技术,但这文章讲的是如何对已有的函数build签名文件,并没有说如何识别main()函数,里面有句
“为了方便用户,我们试图尽最大可能识别main()函数。鉴别这个函数的算法因编译器不同而不同、因程序不同而不同。(DOS/OS2/Windows/GUI/Console...)。
该算法作为一个文本字符串被写入一个特征文件中。遗憾的是,我们还不能自动产生该算法。

     即对于IDA,识别main()不是用一个用sig之类的来定位的,而是用了其他方法。
     
     目前我研究了一下crt0.c 的代码,研究了几个VC编译器生成EXE反汇编后的代码,我写了一个空程序,然后反汇编:
#include <windows.h>
#include <tchar.h>

INT32 WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, PTSTR pcmdLine, INT32 nShowCmd)
{
    return 0;
}

这样里面几乎都是运行库函数的代码了。
   
    所有VC版本,都有五个版本的crt0.c代码,crt0.c, wcrt0.c, wincrt0.c, wwincrt0.c,
dllcrt0.c, dllcrt0.c先不考虑,只考虑四个跟EXE相关的。本质上它们的最终代码实现都
是在crt0.c 中,其余三个只是定义了一下宏然后include 了一下crt0.c,例如wcrt0.c:
/***
*wincrt0.c - C runtime Windows EXE start-up routine
*
*       Copyright (c) 1993-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
*       This is the actual startup routine for Windows apps.  It calls the
*       user's main routine WinMain() after performing C Run-Time Library
*       initialization.
*
*******************************************************************************/

#define _WINMAIN_
#include "crt0.c"

vc2005 和 vc2008 的crt0.c 几乎完全相同,VC6的跟它们不同的多一点。这三个crt0.c中
的__tmainCRTStartup的API调用序列为:
VC6:
ANSI 版本
GetVersion
GetCommandLineA
GetStartupInfoA
GetModuleHandleA
WinMain

UNICODE 版本
GetVersion
__crtGetCommandLineW
GetStartupInfoW
GetModuleHandleA
wWinMain

VC8:
ANSI 版本
GetStartupInfoA
InterlockedCompareExchange
InterlockedExchange
WinMain

UNICODE 版本
GetStartupInfoW
InterlockedCompareExchange
InterlockedExchange
wWinMain

VC9:(跟VC8完全一样)
ANSI 版本
GetStartupInfoA
InterlockedCompareExchange
InterlockedExchange
WinMain

UNICODE 版本
GetStartupInfoW
InterlockedCompareExchange
InterlockedExchange
wWinMain

VC8 VC9 与 VC6 的区别:
VC8 VC9 都没有调用GetModuleHandle,而是用一个常量0x00400000h代替了hInstance;
VC8 VC9 都没有调用GetCommandLine来获得命令行参数,而是用一个二级指针存放命令行
首地址的指针,运行直接可以得到命令行参数。
VC8 VC9 入口点的代码为:
call    __security_init_cookie
jmp     __tmainCRTStartup

VC8 VC9 与 VC6 生成的EXE文件,在"PE"签名的前32字节有一个字符串"Rich"(估计是某位微软牛人的姓氏)

VC8 与 VC9 的区别:
没区别,从CRT到WinMain之间的代码反汇编出来是完全一样的。

以上是目前掌握的信息,下面简述我的寻找WinMain的方法,此方法并没有利用上面提到的
所有信息,
对于VC6, 首先得到入口点,然后在0xD0范围内搜索
push    eax             ; nShowCmd
push    [ebp+lpCmdLine] ; lpCmdLine
push    esi             ; hPrevInstance
push    esi             ; lpModuleName
call    ds:GetModuleHandleA
push    eax             ; hInstance
call    _WinMain@16     ; WinMain(x,x,x,x)

因为VC6 的CRT0.c中调用WinMain是这样的:
mainret = WinMain(GetModuleHandleA(NULL),NULL,...);

对于VC8 VC9 同样先得到入口点,入口点代码如下:
call    __security_init_cookie
jmp     __tmainCRTStartup

得到jmp后的地址,来到__tmainCRTStartup开始处,搜索如下代码:
push    eax             ; nShowCmd
push    esi             ; lpCmdLine
push    0               ; hPrevInstance
push    400000h         ; hInstance
call    _WinMain@16     ; WinMain(x,x,x,x)

四个连续的push指令,和一个常数0x400000,是很重要的特征。
   
    目前思路还很初级,再怎么想觉得无法有新的突破,希望高手路过给点建议

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
不错,学到了不少。
我也要多动动手,做做实验才行!
2008-10-23 17:13
0
游客
登录 | 注册 方可回帖
返回
//