首页
社区
课程
招聘
逆向入口切入[原创]
发表于: 2005-2-14 01:56 12038

逆向入口切入[原创]

nbw 活跃值
24
2005-2-14 01:56
12038

逆向入口切入

作者:nbw
        谨以此菜文献给NE365和FCG。以资新年庆贺!也祝所有圈内人士新年吉祥!

        逆向分析,最开始的一步就是寻找入口点。虽然可以破墙而入,但为了防止“墙后面还是一堵墙”,因此我们还是喜欢去撬门锁。一般来说,破解的话,找一些MessageBox注册提示,网络程序会考虑搞网络api,找到了正确的入口,就可以登堂入室,为所欲为。
        但是一般的软件逆向分析,入口或许稍微难找一些,有时因为找不到正确的分析入口而放弃分析。本次目标是某股票分析软件。
该软件将根据股市信息计算出的数据以柱状显示在坐标系中。我们的目标是找到计算这些数据的代码。找到了这些代码,要弄懂他们就只是时间问题了。
        既然是柱形图显示,希望大家先看一下GDI编程,稍微瞅瞅就行,毕竟这里的关键是找到计算柱形图数据的代码。柱形图变换菜单为“查看”/“显示柱状参数”,因此可以从这个菜单消息入手。
        找菜单消息处理有很多方法,我比较常用相近处理法。因为菜单消息处理函数都离得很近,所以如果可以找到一个菜单的处理地点,其他菜单函数也相应不远了,这就是我所谓的相近处理法,因为我不会脱壳,也懒得学OD那些高级技巧,被逼无奈而已……….
        先运行股票分析软件,经过研究,F7键对应的“今日提示”菜单,有点MessageBox的味道,于是用OD附加进程。下MessageBox断点,在软件中按F7,被OD拦截,Ctrl + F9返回调用处:

0041A64B                push 0                                                       
0041A64D                push 0043B2FC                                        ; |Title = "今日提示"
0041A652                push 00491E80                                        ; |Text = "  …..?...
0041A657                mov ecx,dword ptr ss:[ebp+8]                        ; |
0041A65A                push ecx                                                        ; |hOwner
0041A65B                call dword ptr ds:[42D17C]                        ; \MessageBoxA
0041A661                jmp 00422EB2
       
        继续Ctrl + F9返回上一层调用:

77E1A411                push dword ptr ss:[ebp+18]
77E1A414                push dword ptr ss:[ebp+14]
77E1A417                push dword ptr ss:[ebp+10]
77E1A41A                push dword ptr ss:[ebp+C]
77E1A41D                call dword ptr ss:[ebp+8]            
77E1A420                cmp dword ptr ss:[esp+4],DCBAABCD
77E1A428                je short user32.77E1A43B

        幸运的话这个call dword ptr ss:[ebp+8]或许是菜单消息主处理函数,如果在这里下断点,拦不住其他菜单操作,那可以尝试继续Ctrl + F9返回更上一层调用函数,一直到发现主处理函数。但不幸的是上面代码处于User32.dll领空,更不幸的是对软件的任何操作都会被这个函数拦截,事实上这个函数是消息处理函数,如B哥所说,晃一下鼠标都要被他拦住。
        不过正所谓柳暗花明又一村,如果你乐意,可以在这里下条件断点,但我更愿意继续翻一下最开始的MessageBox 。光标定位在

0041A64B                push 0                ; /Style = MB_OK|MB_APPLMODAL

根据OD提示,该句代码被引发自:

0041A513                mov ecx,dword ptr ss:[ebp-7C]
0041A516                xor eax,eax
0041A518                mov al,byte ptr ds:[ecx+42303F]
0041A51E                jmp dword ptr ds:[eax*4+422FDF]        ;-------典型的消息Table跳转

上面的jmp,是比较典型的条件跳转,根据eax不同,跳向不同位置。在这个地方下断点,会发现一般的操作,软件不会被中断了,说明大部分消息处理都不经过这个地方。但是随便找一个菜单点一下,很明显被断在这个地方。
        那么点一下需要分析的柱形参数菜单,被OD拦截在此,继续单步运行,如下:
0041C47E                movsx edx,word ptr ds:[447102]
0041C485                neg edx
0041C487                sbb edx,edx
0041C489                inc edx
0041C48A                mov word ptr ds:[447102],dx
0041C491                movsx eax,word ptr ds:[447102]
0041C498                test eax,eax
0041C49A                jnz short .0041C4DE                ;------跳

到此:

0041C4DE                push .0043B3A4                                       
省略几句…….
0041C4EF                 mov eax,dword ptr ds:[446C98]
0041C4F4                push eax                                                                ; |hMenu => 02170742
0041C4F5                call dword ptr ds:[42D180]                                ; \ModifyMenuA
0041C4FB                push 0043B3B4                                       
0041C500                push 91                                                                ; |NewItemID = 91 (145.)
0041C505                 push 0                ; |Flags = MF_BYCOMMAND|MF_ENABLED|MF_STRING
省略几句…….
0041C510                call dword ptr ds:[42D174]            ; |\GetMenu
0041C516                push eax                              ; |hMenu
0041C517                call dword ptr ds:[42D180]            ; \ModifyMenuA
0041C545                add edx,97
省略几句…….
0041C54B                mov dword ptr ds:[446CDC],edx
0041C551                push 1                                                ; /Erase = TRUE
0041C553                push  .00446CD0                        ; |pRect = 00446CD0 {732.,-80.,837.,636.}
0041C558                mov eax,dword ptr ss:[ebp+8]                        ; |
0041C55B                push eax                                                                ; |hWnd
0041C55C                call dword ptr ds:[42D188]                                ; \InvalidateRect
0041C562                xor eax,eax
0041C564                jmp  .00422EB2

清注意右边的注释,上面说白了就是修改一下菜单提示内容,然后调用InvalidateRect 函数。再往下就跳出当前函数:

00422EB2                pop esi                               ;  0012FF20
00422EB3                mov esp,ebp
00422EB5                 pop ebp
00422EB6                retn 10

F8单步跟出去:

77E1A41D                call dword ptr ss:[ebp+8]                                ;-----刚才所在的函数
77E1A420                cmp dword ptr ss:[esp+4],DCBAABCD        ;-----返回处
77E1A428                je short user32.77E1A43B                                ;-----跳

到此:

77E1A43B                add esp,8
77E1A43E                pop ebp
77E1A43F                retn 14

继续跟出去,再返回几次,回到主进程领空:

00419B4D                push 0                               ; /MsgFilterMax = 0
00419B4F                push 0                               ; |MsgFilterMin = 0
00419B51                push 0                               ; |hWnd = NULL
00419B53                lea edx,dword ptr ss:[ebp-1C]        ; |
00419B56                push edx                             ; |pMsg
00419B57                call dword ptr ds:[42D1D0]           ; \GetMessageA
00419B5D                test eax,eax
00419B5F                je short  .00419B77
00419B61                lea eax,dword ptr ss:[ebp-1C]
00419B64                push eax                             ; /pMsg
00419B65                call dword ptr ds:[42D1D4]           ; \TranslateMessage
00419B6B                lea ecx,dword ptr ss:[ebp-1C]
00419B6E                push ecx                             ; /pMsg
00419B6F                call dword ptr ds:[42D1D8]           ; \DispatchMessageA
00419B75                jmp short  .00419B4D                                ;-----跳到上面

花3秒钟看一下,上面就是往消息队列放消息。这样看来对于柱形参数菜单软件的处理流程就是:
1、        修改该菜单内容;
2、        调用InvalidateRect 函数;
3、        继续日常消息传送。
由于这个菜单点下以后,可以看到经过计算的柱形股票数据分析。但上面即没有什么高深的计算,连柱形图显示都没发现。
那么先泡一包方便面,郁闷10分钟………..
吃完面,继续研究。既然这个菜单没有什么金子,目前来说,可以考虑一下处理画坐标系的方法,比如可以拦截一下GDI的画图函数,看看软件怎么画那个坐标系。
但翻了一下GDI教程,发现InvalidateRect函数可以引发WM_PAINT消息,从而导致窗口重画。那么看来就是这个函数引发窗体上的坐标系重画。既然如此,下一步就是找到处理WM_PAINT消息的地方。
寻找窗体消息处理,同样有N种方法。但我又要说我不会脱壳,也不会用OD的高级功能。因此慢慢来吧。
这个软件的典型SDK风格让我这个没写过SDK的人也忍不住去看典型的窗体消息处理:

Mov                @stWndClass.lpfnWndProc,offset _ProcWinMain
Mov                @stWndClass.hbrBackground,COLOR_WINDOW + 1
Mov                @stWndClass.lpszClassName,offset szClassName
Invoke        RegisterClassEx,addr @stWndClass
invoke        CreateWindowEx,WS_EX_CLIENTEDGE,offset……(略几个参数)

既然如此,就应该找到CreateWindowEx,然后看一下上面的offset _ProcWinMain。由于N多程序喜欢把关键界面采用子窗口处理,因此还要防止上面的InvalidateRect是处理的子窗口,那样就需要从N个CreateWindowEx函数中找到创建目标子窗口的那一个。
窗口的创建一般在程序初始化时候进行,因此退出软件。用OD加载软件,提示都不理会,中断在入口后,用Ctrl+A让OD分析一下代码。下CreateWindowEx断点,F9运行OD。被中断在CreateWindowEx,返回到主程序领空的调用处(注意用Ctrl+A分析一下那些杂乱op就会显示代码)。
00419C25                push eax                              ; |Width
00419C26                push 32                               ; |Y = 32 (50.)
00419C28                push 64                               ; |X = 64 (100.)
00419C2A                push 0CF0000                        
00419C2F                push  .0043B030                    
00419C34                push  .0043B048                    
00419C39                push 0                                ; |ExtStyle = 0
00419C3B                call dword ptr ds:[42D214]            ; \CreateWindowExA
00419C41                 mov dword ptr ss:[ebp-4],eax

考虑到有子窗口的问题,为了确定该次CreateWindowEx是否创建的是画坐标系的窗口,因此记下返回的窗口句柄值:018D0238 H。
F9继续运行,用窗口spy之类的东东查看一下坐标系所在窗口的句柄,也是018D0238 H,其实坐标系所在窗口就是主窗体。这样,上面分析的WM_PAINT消息触发的就是主窗体,然后重画主窗体上的坐标系。
再温习一下上面的那几句注册窗口的汇编代码,用OD重新加载一下软件,在启动时候找到这个CreateWindowEx上面的RegisterClass,就是这个窗口的注册函数:

00419BD5                mov dword ptr ss:[ebp-8], .0043B014      
00419BDC                mov dword ptr ss:[ebp-4], .0043B020      
00419BE3                lea edx,dword ptr ss:[ebp-28]
00419BE6                push edx                     ; /pWndClass
00419BE7                call dword ptr ds:[42D1CC]          ; \RegisterClassA
00419BED                and eax,0FFFF

上面的00419BE6                push edx 指向窗口的注册信息结构,查一下MSDN,结构定义如下:

typedef struct _WNDCLASS {
    UINT    style;
    WNDPROC lpfnWndProc;                 窗口消息函数地址
    int     cbClsExtra;
    int     cbWndExtra;
    HANDLE  hInstance;
    HICON   hIcon;
    HCURSOR hCursor;
    HBRUSH  hbrBackground;
    LPCTSTR lpszMenuName;
    LPCTSTR lpszClassName;
} WNDCLASS

该结构第2个word就是窗口消息处理函数。结构如下:
0012FEE4   08 00 00 00 6D 9C 41 00 00 00 00 00 00 00 00 00   ...m?.........

根据第2个字节,找到地址 419C6D 。代码如下:

00419C6D                push ebp
00419C6E                mov ebp,esp
00419C70                sub esp,100
00419C76                push esi
00419C77                 movsx eax,byte ptr ds:[446DC9]
00419C7E                test eax,eax
00419C80                 je short  .00419D01                                ;此处跳
00419C82                mov ecx,dword ptr ss:[ebp+C]
00419C85                mov dword ptr ss:[ebp-74],ecx
00419C88                cmp dword ptr ss:[ebp-74],114
00419C8F                ja short  .00419CBF
00419C91                 cmp dword ptr ss:[ebp-74],114         
00419C98                je short  .00419CDC
00419C9A                cmp dword ptr ss:[ebp-74],102
00419CA1                ja short  .00419CB4
00419CA3                cmp dword ptr ss:[ebp-74],100
00419CAA                jnb short  .00419CDC
00419CAC                cmp dword ptr ss:[ebp-74],10
00419CB0                je short  .00419CDC
00419CB2                jmp short  .00419CE6
…………………….

上面的比较,就是比较熟悉的消息比较。如果在最开始地方(00419C6D处)下断点,就会被频繁中断,因为是消息处理最开头嘛。
尝试在几个跳转比较点下断点,会发现上面的

00419C80                 je short  .00419D01                                ;此处跳

会跳转,因此,观察跳转处:

00419D01                mov eax,dword ptr ss:[ebp+C]                ;获取传来的消息
00419D04                mov dword ptr ss:[ebp-78],eax
00419D07                cmp dword ptr ss:[ebp-78],111
00419D0E                ja short  .00419D7E
00419D10                cmp dword ptr ss:[ebp-78],111
00419D17                je  .0041A4DB
00419D1D                cmp dword ptr ss:[ebp-78],4E
00419D21                ja short  .00419D52
00419D23                cmp dword ptr ss:[ebp-78],4E
00419D27                je  .0041A2A4
00419D2D                mov ecx,dword ptr ss:[ebp-78]
00419D30                sub ecx,1                             ;  wm_paint = 0F h
00419D33                mov dword ptr ss:[ebp-78],ecx
00419D36                cmp dword ptr ss:[ebp-78],0E
00419D3A                ja  .00422E98
00419D40                mov eax,dword ptr ss:[ebp-78]        ; 如果wm_paint,此处为 0E h
00419D43                xor edx,edx
00419D45                mov dl,byte ptr ds:[eax+422ECD]
00419D4B                 jmp dword ptr ds:[edx*4+422EB9]

由于我们关心WM_PAINT消息,在windows.h查一下该消息值为:0F H。
上面的00419D01                mov eax,dword ptr ss:[ebp+C] 用来获取传来的消息。我们假定该处获得WM_PAINT消息,也就是0FH。观察一下代码的流向。这里很好观察,但是为了避免出错,你可以把传来的参数硬性改成0FH。到了

00419D4B                 jmp dword ptr ds:[edx*4+422EB9]

再往下:

0041EFEA                mov eax,dword ptr ds:[43CFD4]
0041EFEF                cmp eax,dword ptr ds:[43CFDC]
0041EFF5                jge short  .0041F00B

然后不用细说,F8执行几步就到了处理数据的地方,如果再往下跟踪,就是GDI画图函数,用来将计算出来的数据显示在坐标系里面。
下面就正式登堂入室,可以分析软件如何计算数据,然后将这些数据以图形形式打印在界面上。
分析这些入口点,一般来说需要一些技巧,但是更需要扎实的功底,我一般不太乐意看一些花哨的插件或者高级的用法,当然并不是说那样东西不好,只不过是说采用一些基础的知识,其实可以达到那些目的。基础的知识才是我们需要加强的。
再往下就可以分析软件的算法了。

很多程序的核心算法,都是枯燥的数据运算,如果要搞清楚他们,关键有3点:

1、        找到他们所在的地方;
     这就是本文所讲的东西。

2、        可以理解整个运算过程;
     这是枯燥的跟踪调试,也是最消耗时间很反映个人基础的过程;

3、        理解算法的逻辑。
     看起来这一点没必要,我以前也这么认为。但是后来发现,有些东西,即使理解运算过程,也很难理解运算逻辑,也就是不晓得为什么要那么运算。要做到这一点,就靠触类旁通的天赋+平时的积累。

     因此,诚如一位大侠所说:“终极逆向工程,在于理解对方的整个运算流程和逻辑思维。”吾等小辈,唯有孜孜不倦,才有可能达到终极境界。


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

收藏
免费 7
支持
分享
最新回复 (16)
雪    币: 214
活跃值: (86)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2
应该是好东西,但是………………偶看不明白~~~
2005-2-14 01:58
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
3
我这里讲找到算法的关键部分,但没有时间和精力去逆向出来整个算法,如果有谁愿意通过去逆向他,来加强自己的基础,可以跟我说一下,咱们直接交流一下。不过需要说明的是这个工作或许需要一周时间,但是对提高自身调试能力是有好处的。

联系QQ:   343538175 。验证请说明“交流某算法”
2005-2-14 02:00
0
雪    币: 3686
活跃值: (1036)
能力值: (RANK:760 )
在线值:
发帖
回帖
粉丝
4
支持
2005-2-14 02:47
0
雪    币: 239
活跃值: (160)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
此文应加“精”啦

在分析方法上很详细,值得学习
2005-2-14 03:44
0
雪    币: 97697
活跃值: (200839)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
6
原创支持!
2005-2-14 07:58
0
雪    币: 12342
活跃值: (4055)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
支持
收下学习!
2005-2-14 08:50
0
雪    币: 257
活跃值: (56)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
8
支持
像我这样没有编程功底,虽能看懂但是想不到啊
2005-2-14 11:19
0
雪    币: 253
活跃值: (310)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
再看我会忘记我是谁了
2005-2-14 12:38
0
雪    币: 265
活跃值: (430)
能力值: ( LV9,RANK:370 )
在线值:
发帖
回帖
粉丝
10
支持逆向,好文!
2005-2-14 13:22
0
雪    币: 161
活跃值: (231)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
11
不错,逆向工程是一件费时费力的事情!
2005-2-14 14:56
0
雪    币: 159
活跃值: (89)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
12
支持,以你为目标,努力
2005-2-14 21:34
0
雪    币: 5275
活跃值: (456)
能力值: (RANK:1170 )
在线值:
发帖
回帖
粉丝
13
严重支持,不过泡面还是少吃好!
2005-2-15 00:04
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
14
支持~
2005-2-15 09:52
0
雪    币: 198
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
支持!!!!!!!!!!!!
2005-2-15 10:04
0
雪    币: 200
活跃值: (75)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
16
强啊!向搂主学习了!
2005-2-15 16:12
0
雪    币: 225
活跃值: (146)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
17
顶!  支持.........
2005-2-15 16:39
0
游客
登录 | 注册 方可回帖
返回
//