相关文章推荐
神勇威武的草稿本  ·  为什么Flink ...·  1 月前    · 
爱健身的跑步鞋  ·  Docker多容器连接 ...·  9 月前    · 
文武双全的单车  ·  Spring Boot ...·  1 年前    · 

0x01 定义

main是C/C++的标准入口函数名,程序执行总是从main函数开始,如果有有其他函数,则完成对其他函数的调用后再返回到主函数,最后由main函数结束整个程序,其他函数是不能调用main函数的。在执行程序时,由系统先行调用main函数。

WinMain是windows API窗体程序的入口函数,该函数的功能是被系统调用,作为一个32位应用程序的入口点。WinMain函数应初始化应用程序,显示主窗口,进入一个消息接收一发送循环,这个循环是应用程序执行的其余部分的顶级控制结构。

0x02 区别

二者在同一环境下的不同区别:

Windows支持两种类型的应用程序:

一种是基于控制台用户界面的应用程序(Console User Interface,简称CUI),
另一种是基于图形用户界面的程序(Graphic User Interface,简称GUI)。

0x03 函数详解

3.1 main函数

在 Microsoft C 中,程序启动时调用的函数称为 main。 没有针对 main 声明的原型,可以用零个、两个或三个参数对其进行定义:

int main( void )
int main( int argc, char *argv[] )
int main( int argc, char *argv[], char *envp[] )

其中三个参数的解释如下:

argc 表示有多少个命令行参数,第一个就是执行程序名,所以argc最少为1。 
argv 是具体程序运行的地址与相搭配的参数。 
envp 是系统的环境变量,很少有介绍的。“名称=值”的形式,以NULL结束。

3.2 winmain函数

WinMain是用于应用程序入口点的常规名称,他的句法如下:

int __clrcall WinMain(
  HINSTANCE hInstance,
  HINSTANCE hPrevInstance,
  LPSTR     lpCmdLine,
  int       nShowCmd

其中四个参数的解释如下:

hInstance        类型:HINSTANCE,应用程序当前实例的句柄,也就是他所处的基地址。
hPrevInstance    类型:HINSTANCE,应用程序先前实例的句柄。此参数始终为NULL。
lpCmdLine        类型:LPSTR,应用程序的命令行,不包括程序名称。
nShowCmd         待定

0x04 实验查找

这里用两个程序分别进行查询main函数与winmain函数:

Fport.exe --> main函数

360zipInst.exe --> winmain函数

单独用IDA与OD进行查找:不过还是IDA方便理解一些

4.1 IDA查找main函数

ida打开之后,直接找到start:

反汇编查看伪代码:这里可以看到它是以v7返回值退出的,着重看v7,大部分程序都是以主函数退出:

这里的sub_407D10函数其实就是main函数:

v7 = sub_407D10(dword_41BFC8, dword_41BFCC);

双击步入函数,里面存在相应的命令行显示字符串:

整个的函数逻辑也会存在其中,我们再拿OD调试一下

4.2 OD查找main函数

F8单步运行到这里,观察OD的栈面板窗口,程序运行到 main 函数时,经常会伴随着栈的活动:

这三个数值,其实就是上面所介绍到的main函数的3个参数,来一一对应一下:

Arg1 对应的就是 argc ,表示有多少个命令行参数,第一个就是执行程序名,所以argc最少为1 这里的数值也是 = 00000001

选中 Arg2 ,追踪一下数据:

可以看到数据面板窗口其中就存在着一个物理地址,而这个地址正好对应了 main函数中的 argv ,由于我们运行时,没有搭配任何参数,所以参数为空。

同样的方法,再来看一下Arg3,这里对应的就是相应的系统环境了:

三个参数的数值都可以对应上main函数的参数,那么这里的 Fport.00407D10 也就是整个程序的主入口了

为了进一步证明,F2下个断点,F9运行到断点处,F7进到函数里面:

相应的命令行字符串直接在旁边显示了出来,找对地方了!

4.3 IDA查找winmain函数

这里的操作与上面打开IDA的操作是类似的,直接找到start,进入其中,开启反汇编,查看伪代码:

这里同样是着重看一下,程序是以哪个变量退出的:

很轻松就可以看到这里的变量是v5,后面紧跟着的就是winmain函数,进到函数里面看一下是不是主函数:

很明显,这里的参数值,就是我们先前介绍的 winmain 的句法参数!

4.4 OD查找winmain函数

这里与上面查找main函数的方法亦是同理,F8单步运行到这里,观察OD的栈面板窗口,程序运行到 main 函数时,经常会伴随着栈的活动:

可以看到,在临近exit时,上面出现了四个参数,其实这里的 Arg1 是上面所介绍的 hInstance ,应用程序当前实例的句柄,也就是他所处的基地址,在OD里面可以用 ALT+E 查看程序的基地址:

这里的基地址正好 = 00400000

再来看 Arg2 = 0 ,也对应了上面介绍的始终为 NULL 的 hPrevInstance

同理追踪 Arg3 :

找到第三个参数:lpCmdLine 应用程序的命令行格式:

第四个参数无实意,为了证明此函数为 winmain函数,同样的方法进到函数里面,查看其内容:

成功进入到程序主函数内!

0x05 参考链接

https://www.cnblogs.com/shucome/p/7572142.html
https://blog.csdn.net/m0_37925202/article/details/78944329
https://docs.microsoft.com/zh-cn/windows/win32/api/winbase/nf-winbase-winmain
https://docs.microsoft.com/zh-cn/cpp/c-language/arguments-to-main?view=vs-2019

----------------------------------------------------------------------------
作者:肖洋肖恩、