首页
论坛
课程
招聘
雪    币: 774
活跃值: 活跃值 (209)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝

[原创]第一章:1.1、寻找main函数入口

2010-5-24 18:20 54549

[原创]第一章:1.1、寻找main函数入口

2010-5-24 18:20
54549
逆向的第一步是什么?这要问你学习C语言的第一步是什么,很自然的,逆向的第一步当然也是大名鼎鼎“HelloWorld!”了。但是也不要因此就误认为这一节会很简单,如果你是第一次接触逆向的话,那么这一节还是有些难度的。

      好的,让我们先写一个世界上最出名的程序:

int _tmain(int argc, _TCHAR* argv[])
{
    printf("Hello World!\r\n");
    return 0;
}

      不错!很好的开始!然后用VS2008以Debug方式编译下,再用OllyDbg打开看看:

00411078 >JMP Test_0.004117B0
0041107D  JMP Test_0.00412CC0
00411082  JMP <JMP.&MSVCR90D._lock>
00411087  JMP <JMP.&KERNEL32.GetProcAddress>
0041108C  JMP Test_0.00411440
00411091  JMP Test_0.00413310
00411096  JMP <JMP.&MSVCR90D.?terminate@@YAXXZ>
0041109B  JMP <JMP.&MSVCR90D._exit>
004110A0  JMP <JMP.&KERNEL32.GetCurrentThreadId>
004110A5  JMP <JMP.&MSVCR90D._initterm>

      看看我们的程序停在了什么鬼地方,如果各位初学读者试图从这里就开始分析的话那真的很恐怖,相信30分钟内你的自信心将被打击到零……
      我们都知道其实编译器在编译我们的程序前会做很多准备工作,而这些准备工作由于涉及的东西较多且每个由此编译器生成的程序都一样,因此我们不必深究,只需快速且准确的找到main函数即可。
      但是这对于初学逆向的朋友来说也是最难的,下面我就教各位读者怎样突破这个障碍。
      想要找到main函数,那么我们就要从C语言本身讲起,在刚刚开始学习C语言的时候我们就被不幸的告知,我们的程序中必须要包含一个名字叫做main的函数,不管你多讨厌它都必须如此,后来便成了习惯……
      后来查查C99标准,发现“int main(int argc, char *argv[])”与“int main(void)”都是被接受的,然后又查查MSDN,可以清晰看到一句话“The main and main functions can take the following three optional arguments”,也就是告诉了我们main函数其实是有3个参数的,其后面的例子更是证明了这句话确实是微软写上去的:

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

      嗯,他们又在标准上较劲了,但是考虑到我们大部分程序都是用vs编译的(而且Borland的C++的参数也是如此),因此我们还是做墙头草,随大流吧……

      到这里有的读者可能会感到疑惑,如果我们使用的是符合C99标准的main函数呢?例如我们源码的main函数不就是两个参数吗。但是在这里我要很负责的告诉大家,不管我们代码中实际使用了几个参数,在程序被编译时其main函数肯定是三个参数的,因为这取决于Windows系统的机制。

      因此现在已经为我们识别main函数提供了很好的特征,既有三个参数,且前两个参数为地址量的call就应该是我们的main函数了。除此之外,我们通过MSDN可知应用程序会随着main函数结束而退出,这又给了我们第二个有力的特征,既main函数很定是在程序退出代码附近的(而且目前的主流调试、反汇编工具都可以正确识别出退出函数exit)。

      有了这些特征,我们再想找到main函数就不难了,目前我为大家提供三种方法:

1.1.1、字符串搜索法

      安装完各个版本的C++编译器后,逐个写Hello World,然后用OllyDbg的搜索字符串功能搜索这个字符串,最后逐步回溯即可,下面我为大家演示一下我做的步骤。

      用OllyDbg打开目标文件后,先记住程序默认停在哪里,然后在CPU窗格点击右键,依次选择【超级字符串参考】>【查找ASCII字符】,选择我们的“Hello World”后双击即可到main函数中,代码如下:

004113A0  PUSH EBP                                ; 函数入口
004113A1  MOV EBP, ESP
004113A3  SUB ESP, 0C0
004113A9  PUSH EBX
004113AA  PUSH ESI
004113AB  PUSH EDI
004113AC  LEA EDI, DWORD PTR SS:[EBP-C0]
004113B2  MOV ECX, 30
004113B7  MOV EAX, CCCCCCCC
004113BC  REP STOSD
004113BE  MOV ESI, ESP
004113C0  PUSH Test_0.0041573C                     ; /Hello World!\r\n
004113C5  CALL DWORD PTR DS:[<&MSVCR90D.printf>]   ; \printf
004113CB  ADD ESP, 4
004113CE  CMP ESI, ESP
004113D0  CALL Test_0.00411145
004113D5  XOR EAX, EAX
004113D7  POP EDI
004113D8  POP ESI
004113D9  POP EBX
004113DA  ADD ESP, 0C0
004113E0  CMP EBP, ESP
004113E2  CALL Test_0.00411145
004113E7  MOV ESP, EBP
004113E9  POP EBP
004113EA  RETN

      我们单击选择函数入口后,可以看到CPU窗格下面的信息窗格中显示如下信息:

跳转来自 0041100F

      我们单击选择此信息后,点击鼠标右键,并选择【转到 JMP 来自0041100F】后即可来到上层调用函数(以后我们将之称为“返回到调用”):

0041100A  JMP <JMP.&KERNEL32.DebugBreak>
0041100F  JMP Test_0.004113A0                       ; 我们停到这里
00411014  JMP Test_0.004124E0

      遇到这种情况直接在返回到调用,此时来到真正调用main函数的地方:

0041195F  MOV EAX, DWORD PTR DS:[417148]
00411964  PUSH EAX
00411965  MOV ECX, DWORD PTR DS:[41714C]
0041196B  PUSH ECX
0041196C  MOV EDX, DWORD PTR DS:[417144]
00411972  PUSH EDX
00411973  CALL Test_0.0041100F                     ; 我们停到这里
00411978  ADD ESP, 0C
0041197B  MOV DWORD PTR DS:[41715C], EAX
00411980  CMP DWORD PTR DS:[417150], 0
00411987  JNZ SHORT Test_0.00411995
00411989  MOV EAX, DWORD PTR DS:[41715C]
0041198E  PUSH EAX                                 ; /status => 0
0041198F  CALL DWORD PTR DS:[<&MSVCR90D.exit>]     ; \exit

      通过上面的代码我们便看到了main函数的典型特征,临近exit,且有三个参数。接下来我们要做的就是不断地重复上面的步骤,一直到找到程序入口点为止。

      最后你要做的就是针对不同的版本不同城上的编译器重复上面的步骤,直到收集到你认为足够丰富的信息后结束,从此你就再也不用怕为找不到main函数而苦恼了。

1.1.2、栈回溯法

      栈回溯的方法是先找到main函数中的那个“HelloWorld”,下断点并按【F9】键运行后查看堆栈情况,我这里的堆栈情况如下:

0012FE9C   7C930208  ntdll.7C930208       ; 我们停在这里
0012FEA0   FFFFFFFF
0012FEA4   7FFDE000
0012FEA8   CCCCCCCC
    ……   ……
0012FF64   CCCCCCCC
0012FF68  /0012FFB8
0012FF6C  |00411978  返回到 Test_0.00411978 来自 Test_0.0041100F
0012FF70  |00000001
0012FF74  |003D2C60
0012FF78  |003D2D40
0012FF7C  |0A641DBC
0012FF80  |7C930208  ntdll.7C930208
0012FF84  |FFFFFFFF
0012FF88  |7FFDE000
0012FF8C  |00369E99
0012FF90  |00000000
0012FF94  |00000000
0012FF98  |00130000  ASCII "Actx "
0012FF9C  |00000000
0012FFA0  |0012FF7C
0012FFA4  |00000020
0012FFA8  |0012FFE0  指向下一个 SEH 记录的指针
0012FFAC  |0041107D  SE处理程序
0012FFB0  |0A3788D4
0012FFB4  |00000000
0012FFB8  ]0012FFC0
0012FFBC  |004117BF  返回到 Test_0.004117BF 来自 Test_0.004117D0
0012FFC0  \0012FFF0
0012FFC4   7C817077  返回到 kernel32.7C817077

      对于这些信息我们只需要关注注释前面有“返回到”三个字的,离我们最近是:

0012FF6C  |00411978  返回到 Test_0.00411978 来自 Test_0.0041100F

      鼠标单击选择该项后,按【Enter】键即可来到返回地址00411978处:

0041195F   .  A1 48714100   MOV EAX, DWORD PTR DS:[417148]
00411964   .  50            PUSH EAX
00411965   .  8B0D 4C714100 MOV ECX, DWORD PTR DS:[41714C]
0041196B   .  51            PUSH ECX
0041196C   .  8B15 44714100 MOV EDX, DWORD PTR DS:[417144]
00411972   .  52            PUSH EDX
00411973   .  E8 97F6FFFF   CALL Test_0.0041100F
00411978   .  83C4 0C       ADD ESP, 0C                              ; 我们停在这里
0041197B   .  A3 5C714100   MOV DWORD PTR DS:[41715C], EAX
00411980   .  833D 50714100>CMP DWORD PTR DS:[417150], 0
00411987   .  75 0C         JNZ SHORT Test_0.00411995
00411989   .  A1 5C714100   MOV EAX, DWORD PTR DS:[41715C]
0041198E   .  50            PUSH EAX                                 ; /status => 0
0041198F   .  FF15 80824100 CALL DWORD PTR DS:[<&MSVCR90D.exit>]     ; \exit

      此时我们又来到了这个熟悉的地方,接下来的事情就要各位读者自己发挥了(重复上面的步骤)。

1.1.3、逐步分析法

      以上讲的两种方法都是在学习与知识储备时用的,不可能收到什么实战效果。假如我们现在碰到了一个现在就需要我们分析的软件,而且它的编译环境我们以前没碰到过,这就要求我们纯手工分析并找到main函数了。

      之所以将之称为逐步分析法,是因为我们不需要阅读它代码的具体含义,而是只需要以JMP与CALL为单位逐个跟进,从而根据main函数的特征判定main函数的所在位置。

      其实这种方法有点类似于文件搜索,先搜索根目录、在逐层加深搜索其子目录,直到找到我们需要的东西。

      那我们的程序为例,我们的OEP处就是一个JMP,因此其“根目录”也就是第一层代码里是不可能有我们的main函数了,当我们跟进这个JMP后会发现如下代码:

004117B0   > \8BFF          MOV EDI, EDI
004117B2  /.  55            PUSH EBP
004117B3  |.  8BEC          MOV EBP, ESP
004117B5  |.  E8 96F8FFFF   CALL Test_0.00411050
004117BA  |.  E8 11000000   CALL Test_0.004117D0
004117BF  |.  5D            POP EBP
004117C0  \.  C3            RETN

      我们发现第二层代码里也没有我们的main函数,但是有两个CALL。因此我们跟进第一个CALL中,为了节省篇幅,我在这里就不贴出代码了,我在这里并没有发现main函数,但是发现了数个JMP与CALL。不过需要注意的是,我们一定要注意采用逐层搜索的思想,因此这里的CALL与JMP就不要再继续跟下去了,我们现在要住的是返回上一层,看看第二个CALL里是什么:

004117D0  MOV EDI, EDI
004117D2  PUSH EBP
004117D3  MOV EBP, ESP
004117D5  PUSH -2
    ……  ……
00411813  CALL Test_0.004110FF
    ……  ……
00411830  CALL DWORD PTR DS:[<&KERNEL32.Interlocke>;  kernel32.InterlockedCompareExchange
    ……  ……
0041184E  JMP SHORT Test_0.0041185D
00411850  PUSH 3E8                                 ; /Timeout = 1000. ms
00411855  CALL DWORD PTR DS:[<&KERNEL32.Sleep>]    ; \Sleep
0041185B  JMP SHORT Test_0.00411825
    ……  ……
004118EB  PUSH Test_0.004157C8                     ;  _
004118F0  PUSH 0
004118F2  PUSH 1F4
004118F7  PUSH Test_0.00415750                     ;  f
004118FC  PUSH 2
004118FE  CALL DWORD PTR DS:[<&MSVCR90D._CrtDbgRep>;  MSVCR90D._CrtDbgReportW
00411904  ADD ESP, 14
    ……  ……
00411913  PUSH 0                                   ; /NewValue = 0
00411915  PUSH Test_0.0041756C                     ; |pTarget = Test_0.0041756C
0041191A  CALL DWORD PTR DS:[<&KERNEL32.Interlocke>; \InterlockedExchange
    ……  ……
00411929  PUSH Test_0.00417590
0041192E  CALL Test_0.00411172
00411933  ADD ESP, 4
    ……  ……
0041193A  PUSH 0
0041193C  PUSH 2
0041193E  PUSH 0
00411940  CALL DWORD PTR DS:[417590]                ; 注意这里,虽然这个CALL也有三个参数,但是仔细分析一下我们就会发现
00411940                                            ; 这并不是main函数,因为main函数的后两个参数是指针,这里的0与2显然
00411940                                            ; 不符合要求。其次他也并非是临近exit的。
00411946  PUSH 1
00411948  CALL DWORD PTR DS:[<&MSVCR90D._CrtSetChe>;  MSVCR90D._CrtSetCheckCount
    ……  ……
0041195F  MOV EAX, DWORD PTR DS:[417148]
00411964  PUSH EAX
00411965  MOV ECX, DWORD PTR DS:[41714C]
0041196B  PUSH ECX
0041196C  MOV EDX, DWORD PTR DS:[417144]
00411972  PUSH EDX
00411973  CALL Test_0.0041100F                     ; 终于来到我们熟悉的main函数里了!
00411978  ADD ESP, 0C
    ……  ……
0041198E  PUSH EAX                                 ; /status => 0
0041198F  CALL DWORD PTR DS:[<&MSVCR90D.exit>]     ; \exit
    ……  ……
0041199E  CALL DWORD PTR DS:[<&MSVCR90D._cexit>]   ;  MSVCR90D._cexit
    ……  ……
004119AB  JMP SHORT Test_0.004119FF
    ……  ……
004119B7  MOV ECX, DWORD PTR SS:[EBP-14]
004119BA  PUSH ECX
004119BB  MOV EDX, DWORD PTR SS:[EBP-28]
004119BE  PUSH EDX
004119BF  CALL Test_0.00411181
004119C4  ADD ESP, 8
004119C7  RETN

      看到这里各位读者是不是感觉逆向很简单,但也充满挑战?如果你掌握了以上三种方法,那么恭喜你,你已经成功的走出了第一步,这很有纪念意义。

【返回到目录】:http://bbs.pediy.com/showthread.php?t=113689

[看雪官方培训]《安卓高级研修班(网课)》9月班开始招生!顶尖技术、挑战极限、工资翻倍!

最新回复 (78)
雪    币: 1054
活跃值: 活跃值 (10)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
gaollxu 活跃值 2 2010-5-24 20:02
2
0
第一次坐沙发,哈哈。
刚试过了,堆栈法以前没用过。

期待其它文章。
雪    币: 216
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
孔子后裔 活跃值 2010-5-24 20:32
3
0
呵呵,看完了,就是记不住啊
雪    币: 13
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Greater 活跃值 2010-5-24 20:51
4
0
hha 不错啦 楼主很是实在啊 很有用的东西啦
雪    币: 327
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
ghban 活跃值 2010-5-24 21:06
5
0
不错不错 LZ 辛苦了!
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Cove 活跃值 2010-5-25 02:17
6
0
mark一下。。

可以慢慢看了
雪    币: 230
活跃值: 活跃值 (11)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
lonkil 活跃值 1 2010-5-25 03:53
7
0
,   楼主的治学很严谨,看过楼主的不少好文章。支持一下,再接再厉,哈哈。
雪    币: 207
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
flong 活跃值 2010-5-25 08:52
8
0
很好,楼主开始了一个新方向,将逆向系统化,条理化。
雪    币: 774
活跃值: 活跃值 (209)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
A1Pass 活跃值 5 2010-5-25 09:09
9
0
希望能借这位朋友吉言,可以让这套教程有些意义。

-------------------------------------------------------
本教程是边写作,边发表,因此各位如果觉得在整体结构上哪里需要调整,或有什么好的建议,还望各位不惜赐教,让我们在交流中提高自己,服务大家。
雪    币: 26
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zlws 活跃值 2010-5-25 09:17
10
0
通俗易懂 辛苦
如果能先科普下程序在执行main函数前系统都做了些啥,那就更perfect了
雪    币: 13
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jasonzhou 活跃值 2010-5-25 09:38
11
0
看来逆向的门槛将会越来越低了
雪    币: 65
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
yasm 活跃值 2010-5-25 12:56
12
0
如果都能高质量的完成,也算是很好很好的一件事了,论坛上这样能让我们新手看的文章,现在不是很多。谢谢LZ。
雪    币: 223
活跃值: 活跃值 (10)
能力值: ( LV11,RANK:188 )
在线值:
发帖
回帖
粉丝
XPoy 活跃值 3 2010-5-25 14:37
13
0
找main的主要方法是
在开始的那段中找关闭进程的API调用,exit/ exitprocess/ TerminateProcess之类。在其前的调用通常是 main

还有找DLL的入口,loadlibrary调用的lpkloaddll在调用dll入口之前是
call ebx这样调用DLL入口的,所以OD挂个DLL直接执行到此DLL main的返回位置,retn之后就得到了本机上 中loadlibrary调用  dll main的关键点,因为user32.dll总是最早载入,本机上可以是一直用。
雪    币: 65
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
yasm 活跃值 2010-5-25 20:47
14
0
我个人觉得,DEBUG和RELEASE,如果从一开始就放在一起对比(工作量就大了)会比较好。

当然分析DEBUG再加上PDB是件相对比较容易的事情。

第一次分析main之前的动作,可以多次进入CALL,根据OD提示的API参考MSDN,也就大概知道编译器在main之前所做的工作了。

如果要往下深入,我想分析RELEASE是必然的,如果从一开始就熟悉编译器的优化方式,对以后的分析能够起到比较好的作用。

我也是初学中的初学,一点愚见,如果有什么问题,请谅解。
雪    币: 774
活跃值: 活跃值 (209)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
A1Pass 活跃值 5 2010-5-25 21:22
15
0
回复13楼的XPoy
      非常感谢你提出的建议,其实我也一直在想,本篇文章作为开篇,怎样写会比较好一些,应不应该带上DLL入口相关的内容。但是后来自己仔细论证了一下,我感觉第一篇文章作为整个教程的一个基调,切不可贪多。一定要做到有目的的写作,也就是说我的教程究竟想教会别人做什么。
     我感觉,我的教程所面向的对象仍然是以基础薄弱,刚入门的读者为主,因此我要做的事情仅仅是让他们了解最为重要的、最为迫切的知识。修剪枝蔓才能确立主干,既然我们的立足点是逆向工程,那么就应该尽量减少其他附加知识的,以降低阅读门槛。

回复14楼的yasm
     首先非常感谢你的反馈,你说的观点也没什么问题,对于Release版,我想在第一篇文章就出现会吓到很多读者,我在后面的教程中会逐步引入的。
雪    币: 223
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sunson 活跃值 2010-5-25 23:27
16
0
学习了,终于看到通俗易懂的教程了
雪    币: 206
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
newskrq 活跃值 2010-5-26 08:01
17
0
谢谢楼主,可以系统的深层次的学习一下了
雪    币: 233
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ANight 活跃值 2010-5-26 09:23
18
0
LZ 文章写的不错 !值得期待
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tntCHEN 活跃值 2010-5-26 15:48
19
0
楼主很强大!!!!!
雪    币: 226
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zhangworld 活跃值 2010-5-26 16:00
20
0
严重期待,希望不要等太久...学习ing
雪    币: 100
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ceydj 活跃值 2010-5-26 16:01
21
0
hha 不错啦 楼主很是实在啊 很有用的东西啦
雪    币: 774
活跃值: 活跃值 (209)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
A1Pass 活跃值 5 2010-5-27 01:05
22
0
本教程计划2-3天跟新一篇(事情很多,否则就天天更新了),估计最多不会超过3个月就会更新完毕的。

如果各位初学你想的朋友能从今天开始跟着本教程一直学下去,三个月后相信你会脱胎换骨的。
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
补丁 活跃值 2010-5-27 14:19
23
0
太好了,学习!!!!!!
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
limingzhu 活跃值 2010-5-27 23:47
24
0
谢谢分享~~ 我新手对我很有帮助
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bbstz 活跃值 2010-5-28 16:04
25
0
学习了,哈哈~
雪    币: 204
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yungtain 活跃值 2010-5-29 16:14
26
0
我等新手,受益匪浅啊,谢谢楼主!
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zzycqok 活跃值 2010-6-1 12:21
27
0
顶楼主。先顶后看。
雪    币: 430
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
山村小子 活跃值 4 2010-6-1 13:10
28
0
不错不错 LZ 幸苦了!
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zzycqok 活跃值 2010-6-1 14:29
29
0
看完了,感觉非常好。
以前总是感觉一进入ollaydbg,找不着头脑,终于有点头绪了。
谢谢楼主。
雪    币: 142
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ttkkxx 活跃值 2010-6-1 19:19
30
0
我们单击选择函数入口后,可以看到CPU窗格下面的信息窗格中显示如下信息:

跳转来自 0041100F

      我们单击选择此信息后,点击鼠标右键,并选择【转到 JMP 来自0041100F】后即可来到上层调用函数(以后我们将之称为“返回到调用”):
=============================================
我有一个非常白痴的问题,
就是我用VC6的时候可以在信息框格中看见这个信息,
可是我用VC2008 VC2010的时候却没有这个返还信息,
这是什么原因,
而且这个问题不仅仅是这个程序,
我以前调试完美这个游戏的时候,那个做视频教程的都有这个返还的提示,
可是就是我的没有,
我百度 谷歌都没解啊。
望指教。
雪    币: 774
活跃值: 活跃值 (209)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
A1Pass 活跃值 5 2010-6-2 01:01
31
0
我本文描述的操作都是在OllyDbg里
雪    币: 142
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ttkkxx 活跃值 2010-6-2 06:53
32
0
抱歉,我没有说清楚,就是我用OD调试VC6编译出来的东西,会出现“跳转来之什么什么地方”
而用OD调试VS2008,VS2010的时候就没有这个提示,如果没有这个提示是什么原因,
或者有什么解决方案。
上传的附件:
雪    币: 774
活跃值: 活跃值 (209)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
A1Pass 活跃值 5 2010-6-2 08:29
33
0
这个问题我没碰到过,你可以检查一下你的【选项】>【调试选项】>【CPU】,看看此选项卡下面的所有复选框是否为选中状态,如果不是将其全部勾选上。
雪    币: 211
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sando 活跃值 2010-6-2 08:46
34
0
不错,分析得很好,学习了!
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zzycqok 活跃值 2010-6-2 09:51
35
0
我也没有显示,后来通过以下方法达到类似的效果。
在main函数中的某一点,增加一个断点,运行时,函数停在断点处,[查看]--》[调用堆栈],打开堆栈窗口(快捷键Alt+K),在调用栈可以看到所有的调用过程,如果不对的话,在调用栈窗口,点右键,有一个线程按钮,进去选择不同的线程。
然后选择某个函数,右键,就有[显示调用],[显示过程]等命令。
ps:我看了我的调试设置,cpu中的[显示跳转路径]也check上了,但不知道为什么没有显示出来。
难道和版本有关?这就不得而知了,我的版本是ollyice v1.1 汉化第二版 汉化:cao_cong
雪    币: 779
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
RogerWood 活跃值 2010-6-2 10:05
36
0
楼主写的很好.赞一个
雪    币: 142
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ttkkxx 活跃值 2010-6-2 13:30
37
0
谢谢了,还是不行,我真的怀疑是版本的问题,把
雪    币: 20
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
万年憨猿 活跃值 2010-6-8 01:25
38
0
看帖留名,看过楼主的opcode文章,最近才注意到出专题了,支持!
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
palap 活跃值 2010-6-13 23:27
39
0
好东东,感谢楼主,学习中。。
雪    币: 142
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
大色秘密 活跃值 2010-6-14 13:44
40
0
顶一个,支持楼主!
雪    币: 19
活跃值: 活跃值 (35)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
叁毛 活跃值 1 2010-6-14 20:43
41
0
1、首先感谢作者的辛勤劳作。
2、希望看雪有更多像作者这样的人,为大家贡献。

我不得不说几句,其实LZ现在做的这些东西,网上已经很多资料了,比如《加密解密3》《夜读天书》、《黑客反汇编揭秘》、《IDA权威指南》还有论坛很多前人的杰作。希望作者结合这些人的精华,把文章写得更好。

我的建议:

1、以后再写文章的时候,比如类似这样的话“但是在这里我要很负责的告诉大家,”就不要加进来了,因为作为一篇学术论文(或许你不是这么认为),是不需要这些的,你应该拿出实据来说明。你可以引用C99的原话,“It shall be defined with a return type of int and with no parameters:......or in some other implementation-defined manner.”C99在这里只是“Shall be”,不是“must be”,所以给编译器的厂家很大空间,并不违背了C99的标准。
2、尽可能结合更多编译器,来说明C/C++的本质。
雪    币: 774
活跃值: 活跃值 (209)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
A1Pass 活跃值 5 2010-6-17 11:48
42
0
非常感谢 叁毛 对本文提出的建议,并非常高兴看到有人认可我的劳动成果。
本回复对事不对人,心理承受能力差者请过滤:

接受的建议:
第一条建议我接受,虽然正像你说的那样我并没有把自己的文章当成学术论文来看待,但是正规一点还是好的。
第二条建议我接受50%,首先编译原理是一样的,而VC与其他编译器生成代码上的大体上的异同个人感觉只需几百字即可说明白,而且网上也有类似资料。
                     我接受的是你提出自己建议的初衷,希望文中的例子有对比,行文有起伏,这些我以后会着重考虑。

我的想法 ^_^ :
首先说我写的东西,我本人是一个非常反对重复发明轮子的人,当我认为自己有能力查缺补漏,并完善某个知识点时,我才会去做这件事情。晚辈斗胆在此列出 叁毛 兄提出的哪些书籍,并分别就反汇编这块说说自己的看法,不对之处还望指正。

《加密解密3》:很明显第四章的主要目的不是教会读者分析代码,而是纵观结构与逻辑(例如没有细节、没有C++类相关内容)。
《天书夜读》:这个不多作评论,笔者仅仅用了十几页来描述逆向,很显然只是想给读者建立一个概念而已。
《黑客反汇编揭秘》:简单的说一下吧,分支结构那里,那本书有关于二叉树相关的例子就列出数种情况,而我的文章中只给了一种情况,只为更利于读者读懂。
《IDA权威指南》:本书笔者刚好读完第八章,笔者纵观整书目录只发现第8.7节与第20章描述的内容只算与逆向勉强相关。

    因此我也不得不说,不知道这些书 叁毛 兄是怎么理解的,其中两本个人认为与逆向的关系简直是微乎其微。
    而单单就《加密解密3》与《黑客反汇编揭秘》这两本书来说,一个是为了破解打基础(请看那部书后面的章节),一个是面向专业的逆向人员。
    但我的文章是面向对于逆向工程有兴趣的读者写的,他们并不专业,他们的知识很不系统,因此我的文章的目的就是帮他们穿针引线,就是让他们以后能看懂类似于《黑客反汇编揭秘》这种书。

    当然,相信 叁毛 兄是抱着一颗赤诚之心对本文提出建议的,因此特将 叁毛 ID列于本系列教程之首页,以表最诚挚的感谢!!
雪    币: 15
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jenf 活跃值 2010-6-17 12:05
43
0
楼主好人 学习ing
雪    币: 19
活跃值: 活跃值 (35)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
叁毛 活跃值 1 2010-6-18 22:40
44
0
谢谢你。

我的小小的建议被你采纳,我觉得是本人最大的荣幸。

可能跟我水平有关系吧,对这几本书的理解跟你的理解不一样。
不管如何,LZ能否无偿地将这些总结,并跟大家分享的这种精神是可贵的。

我这里以前收集了一些资料,希望对你有用。
上传的附件:
雪    币: 774
活跃值: 活跃值 (209)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
A1Pass 活跃值 5 2010-6-19 11:20
45
0
感谢 叁毛 提供的资料~~
雪    币: 271
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wep 活跃值 2010-6-19 11:49
46
0
非常感谢LZ做一些让初学者易于接受的教程。很不错。收了。
雪    币: 655
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
为静而生 活跃值 2010-6-19 12:19
47
0
mark之~~
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
落雪非花 活跃值 2010-6-20 21:43
48
0
学习中,加油
雪    币: 237
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ysouyno 活跃值 2010-6-21 22:46
49
0
我们单击选择函数入口后,可以看到CPU窗格下面的信息窗格中显示如下信息:

跳转来自 0041100F

      我们单击选择此信息后,点击鼠标右键,并选择【转到 JMP 来自0041100F】后即可来到上层调用函数(以后我们将之称为“返回到调用”):


按教程操作到此,找不到”跳转来自 XXXXXXXX“,无法进入上层调用函数啊?请指点一下
雪    币: 237
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ysouyno 活跃值 2010-6-21 23:04
50
0
[QUOTE=zzycqok;817384]我也没有显示,后来通过以下方法达到类似的效果。
在main函数中的某一点,增加一个断点,运行时,函数停在断点处,[查看]--》[调用堆栈],打开堆栈窗口(快捷键Alt+K),在调用栈可以看到所有的调用过程,如果不对的话,在调用栈窗口,点右键,有一个线程按钮,进去选择不同的线程。
然后选择某个函数...[/QUOTE]

谢谢,这个方法还是可以实现的!
游客
登录 | 注册 方可回帖
返回