zoukankan      html  css  js  c++  java
  • OD附加功能分析

    OD版本:OllyICE v1.10

     

    在从文件菜单选择附加后,OD会在注册一个窗口类后,先创建一个0x138大小的进程表再是CreateWindowExA 创建窗口;

     

    00478013 loc_478013:                            

    00478013                 push    0               ; int

    00478015                 push    offset sub_477C10 ; int

    0047801A                 push    100h            ; int

    0047801F                 push    310h            ; int

    00478024                 push    offset asc_4C20E8 ; "?

    00478029                 push    offset byte_4ED3FC ; dest

    0047802E                 call    _Createsorteddata     //此处为创建进程表

     

    表的结构体如下:

    table           struc ; (sizeof=0x138)

    name            db 260 dup(?)   //表的名字

    count       dd ?                //表中保存的数据个数

    maxcount        dd ?           //表能保存的最大数量

    currentobj      dd ?            //当前选中的表中数据的ID,未选中时为为-1

    addrcurobj       dd ?             //当前选中数据的地址,未选中时为0

    size            dd ?            //表中每个数据的大小

    field_118       dd ?

    baseaddrobj           dd ?      //表中保存的数据的基地址

    fncmp              dd ?        //函数首地址

    field_124       dd ?

    field_128      dd ?    

    sign            dd ?   //标志位,表示是否有索引数据(也就是baseaddroffset是否有效)

    baseaddroffset        dd ?       //索引数据,标示每个数据在表中的顺序

    field_134       dd ?

    table           ends

     

     

    然后OD会获取自己的进程ID号,并获取EnumProcesses ,EnumProcessModules,GetModuleFileNameExA 三个函数的地址;

     

     

    00475138 loc_475138:                            

    00475138                 xor     ebx, ebx

    0047513A                 call    GetCurrentProcessId  //获取OD本身的进程ID

    0047513F                 mov     [ebp+var_10], eax

    00475142                 mov     eax, dword_4D5A0C

    00475147                 test    eax, eax

    00475149                 jz      loc_4752AF

    0047514F                 push    offset aEnumprocesses ; "EnumProcesses"

    00475154                 push    eax             ; hModule

    00475155                 call    GetProcAddress//获取EnumProcesses地址

    0047515A                 mov     edi, eax

    0047515C                 push    offset aEnumprocessm_0 ; "EnumProcessModules"

    00475161                 mov     eax, dword_4D5A0C

    00475166                 push    eax             ; hModule

    00475167                 call    GetProcAddress//获取EnumProcessModules的地址

    0047516C                 mov     [ebp+var_20], eax

    0047516F                 push    offset aGetmodulefil_0 ; "GetModuleFileNameExA"

    00475174                 mov     edx, dword_4D5A0C

    0047517A                 push    edx             ; hModule

    0047517B                 call    GetProcAddress//获取GetModuleFileNameExA地址

    00475180                 mov     [ebp+var_24], eax

     

     

    之后OD枚举系统中的所有进程并保存枚举到的进程;

     

    004751A3                 push    eax

    004751A4                 push    400h

    004751A9                 push    edx

    004751AA                 call    edi   // EnumProcesses  枚举进程

    004751AC                 test    eax, eax

    004751AE                 jnz     short loc_4751B3

     

     

    接着再一个循环中OD会尝试利用OpenProcess打开枚举到的所有进程,如果进程ID不等于OD本身ID 并且OpenProcess函数返回成功的话,OD会利用EnumProcessModules枚举模块并获取第一个模块句柄,如果EnumProcessModules返回成功,OD会利用GetModuleFileNameExA获取模块全路径,最后把进程ID和 模块全路径 按顺序保存到上面建立的 进程表 中; 

     

    004751DB loc_4751DB:                             

    004751DB                 mov     eax, [edi]

    004751DD                 cmp     eax, [ebp+var_10]// 判断是否等于OD本身ID

    004751E0                 jz      loc_47529B

    004751E6                 push    eax             ; dwProcessId

    004751E7                 push    0               ; bInheritHandle

    004751E9                 push    410h            ; dwDesiredAccess

    004751EE                 call    OpenProcess

    004751F3                 mov     [ebp+hObject], eax

    004751F6                 cmp     [ebp+hObject], 0//判断进程是否打开成功

    004751FA                 jz      loc_47529B

    00475200                 lea     edx, [ebp+var_C]

    00475203                 lea     ecx, [ebp+var_1C]

    00475206                 push    edx

    00475207                 push    4

    00475209                 push    ecx

    0047520A                 mov     eax, [ebp+hObject]

    0047520D                 push    eax

    0047520E                 call    [ebp+var_20] //EnumProcessModules枚举进程模块

    00475211                 test    eax, eax

    00475213                 jnz     short loc_475220

    00475215                 mov     edx, [ebp+hObject]

    00475218                 push    edx             ; hObject

    00475219                 call    CloseHandle//如果EnumProcessModules不成功则关闭句柄

    0047521E                 jmp     short loc_47529B

     

     

    如果EnumProcessModules成功则走如下分支

     

    00475220 loc_475220:                          

    00475220                 mov     ecx, [edi]      ; int

    00475222                 xor     eax, eax        ; int

    00475224                 mov     dword ptr [ebp+arglist], ecx//把进程ID保存到一临时结构体中

    0047522A                 lea     edx, [ebp+var_528]

    00475230                 mov     [ebp+var_730], 1

    0047523A                 mov     [ebp+var_72C], eax

    00475240                 mov     [ebp+var_528], 0

    00475247                 push    104h

    0047524C                 push    edx

    0047524D                 mov     ecx, [ebp+var_1C]

    00475250                 push    ecx

    00475251                 mov     eax, [ebp+hObject]

    00475254                 push    eax

    00475255                 call    [ebp+var_24]//GetModuleFileNameExA获得模块路径

    00475258                 mov     [ebp+var_425], 0

    0047525F                 mov     edx, [ebp+hObject]

    00475262                 push    edx             ; hObject

    00475263                 call    CloseHandle//关闭打开的进程句柄

    00475268                 push    0

    0047526A                 lea     ecx, [ebp+var_728]

    00475270                 push    ecx

    00475271                 push    0

    00475273                 push    0

    00475275                 lea     eax, [ebp+var_528]

    0047527B                 push    eax

    0047527C                 call    004A51BC   //把模块路径复制到临时变量结构体中

    00475281                 add     esp, 14h

    00475284                 lea     edx, [ebp+arglist] ; int

    0047528A                 mov     [ebp+var_628], 0

    00475291                 push    edx             ; arglist

    00475292                 push    esi             ; src

    00475293                 call    _Addsorteddata //把包含了进程ID与模块路径的临时结构体添加到进程表中

    00475298                 add     esp, 8

     

    0047529B loc_47529B:                                                               

    0047529B                 inc     [ebp+var_4]

    0047529E                 add     edi, 4

    004752A1                 mov     ecx, [ebp+var_4]

    004752A4                 cmp     ecx, [ebp+var_8] //检查比较次数是否小于枚举到的进程个数

    004752A7                 jl      loc_4751DB //小于则继续循环

     

               

     

    枚举完进程后接着检查进程表中保存的数据是否小于等于0;如果小于等于则直接返回;

    反之则EnumWindows,并利用GetWindowText函数获取桌面窗口的标题

    保存到 进程表中 对应的进程数据中

    004753E9              cmp     dword ptr [esi+104h], 0//比较进程表中数据是否小于0

    004753F0              jle     short loc_4753FD

    004753F2              push    esi       //此处的参数是 进程表的首地址

    004753F3              push    offset sub_477A90 ; lpEnumFunc

    004753F8              call    EnumWindows

     

     

     

    以下是EnumWindowsProc的功能

    00477AA8                 lea     edx, [ebp+dwProcessId]

    00477AAB                 push    edx             ; lpdwProcessId

    00477AAC                 mov     ecx, [ebp+hWnd]

    00477AAF                 push    ecx        //枚举的窗口进程的句柄

    00477AB0                 call    GetWindowThreadProcessId //获得窗口的进程ID

     

     

    下面是个循环 利用上面得到的进程ID与进程表中保存的进程ID做比较,如果相等 则GetWindowTextA获得窗口标题,并把得到的数据保存在进程表中对应的位置

    00477ABB loc_477ABB:                             ; CODE XREF: sub_477A90+75j

    00477ABB                 mov     edx, [ebx]

    00477ABD                 cmp     edx, [ebp+dwProcessId]

    00477AC0                 jnz     short loc_477AF8

    00477AC2                 cmp     byte ptr [ebx+10Ch], 0

    00477AC9                 jnz     short loc_477AF8

    00477ACB                 push    100h            ; nMaxCount

    00477AD0                 mov     ecx, eax

    00477AD2                 lea     eax, [ecx+eax*2]

    00477AD5                 shl     eax, 4

    00477AD8                 add     eax, ecx

    00477ADA                 shl     eax, 4

    00477ADD                 add     esi, eax

    00477ADF                 add     esi, 10Ch

    00477AE5                 push    esi  //buffer既为进程表中不同进程对应的数据地址

    00477AE6                 mov     eax, [ebp+hWnd]

    00477AE9                 push    eax             ; hWnd

    00477AEA                 call    GetWindowTextA  //获得枚举的窗口的标题并保存到进程表中对应的进程数据中

     

    00477AEF                 mov     byte ptr [ebx+20Bh], 0

    00477AF6                 jmp     short loc_477B07获得后跳出循环 利用枚举到的下一个窗口再次执行此函数

     

     

    如果进程ID不相等则继续循环

    00477AF8                 inc     eax

    00477AF9                 add     ebx, 310h  0x310为结构体大小

    00477AFF loc_477AFF:                           

    00477AFF                 cmp     eax, [edi+104h] //检查比较的次数 是否大于进程表中 的进程数

    00477B05                 jl      short loc_477ABB

     

    在EnumWindows函数执行完成返回后,OD会调用InvalidateRect函数,使显示进程的窗口重绘;

    004782F8                 push    0               ; bErase

    004782FA                 push    0               ; lpRect

    004782FC                 mov     edx, dword_4ED3F8

    00478302                 push    edx             ; hWnd

    00478303                 call    InvalidateRect

     

     

    OD会对进程表中的 ID号,把相对应的索引数据进行从小到大的排序..

    004AC501                 jz      short loc_4AC51C

    004AC503                 mov     edx, [ebp+fcmp]

    004AC506                 mov     ecx, [ebp+nelem]

    004AC509                 push    ecx //第一个参数为进程表中的数据个数

    004AC50A                 mov     dword_50A5F8, edx

    004AC510                 mov     eax, [ebp+base] //第二个参数为进程表中索引数据的首地址

    004AC513                 push    eax

    004AC514                 call    sub_4AC310

    最终函数会调用到进程表结构体中偏移0x120位置保存的函数地址;

     

     

    当从进程窗口列表框中选择要附加的进程并点击附加按钮后,OD会记录其序号,并通过序号计算出此进程在 进程表中的 偏移位置,通过偏移位置得到进程ID

     

    004784A5                 mov     eax, dword_4ED508//得到要附加进程在列表框中的位置

    004784AA                 test    eax, eax

    004784AC                 jl      loc_47867B//如果进程号小于0则直接返回;

    004784B2                 cmp     eax, dword_4ED500/比较序号是否大于进程总数

    004784B8                 jge     loc_47867B  //大于也直接返回

    004784BE                 mov     edx, dword_4ED52C

    004784C4                 mov     esi, [edx+eax*4]

    004784C7                 imul    esi, dword_4ED510

    004784CE                 add     esi, dword_4ED518 //上面几步是计算得出附加的进程在进程表中存储的首地址

    004784D4                 mov     eax, [esi]  //得到进程ID

    004784D6                 cmp     eax, dword_4D5A70 //判断OD是否正在调试此程序

    004784DC                 jnz     short loc_4784F4

     

     

    如果此时OD正在调试此程序则会弹出一错误框提示 进程“xxxx”是你正在调试的程序……

    并直接返回。

     

    004784DE                 add     esi, 0Ch

    004784E1                 push    esi             ; arglist

    004784E2                 push    offset asc_4C2122 ; "?

    004784E7                 call    _Error

    004784EC                 add     esp, 8

    004784EF                 jmp     loc_47867B//直接返回..

     

     

    接着OD会申请一定的空间并初始化一些表,如:dll句柄表,线程表,统计表,等等

     

    004784F4 loc_4784F4:                           

    004784F4                 push    1

    004784F6                 call    sub_4758A4

    004784FB                 pop     ecx

    004784FC                 test    eax, eax

    004784FE                 jnz     loc_47867B

    00478504                 call    sub_47540C //此函数用于申请空间并初始化表

    00478509                 test    eax, eax //判断是否初始化成功。

    0047850B                 jz      short loc_47851D

    0047850D                 push    offset aIFUC    ; "无法分配足够内存"

    00478512                 call    _Error//如果不成功则会报告内存内存不足…并直接返回

    00478517                 pop     ecx

    00478518                 jmp     loc_47867B

     

     

    0046b258这个函数中OD会根据用户设置的导入库保存在ollydbg.ini文件中的[Import libraries]项解析调试程序中的库函数;

    下面就是处理的一个循环过程

     

    0046B268 loc_46B268:                          

    0046B268                 push    ebx

    0046B269                 lea     eax, [edi+4F8h]

    0046B26F                 push    eax             ; format

    0046B270                 lea     edx, [esp+318h+buffer]

    0046B277                 push    edx             ; buffer

    0046B278                 call    _sprintf

    0046B27D                 add     esp, 0Ch

    0046B280                 push    offset FileName ; lpFileName

    0046B285                 push    104h            ; nSize

    0046B28A                 lea     ecx, [esp+318h+path]

    0046B28E                 push    ecx             ; lpReturnedString

    0046B28F                 lea     eax, [edi+4]

    0046B292                 push    eax             ; lpDefault

    0046B293                 lea     edx, [esp+320h+buffer]

    0046B29A                 push    edx             ; lpKeyName

    0046B29B                 lea     ecx, [edi+503h]

    0046B2A1                 push    ecx             ; lpAppName

    0046B2A2                 call    GetPrivateProfileStringA  //得到ollydbg.ini 文件中[Import libraries]项中的路径

    0046B2A7                 cmp     [esp+310h+path], 0

    0046B2AB                 jz      short loc_46B2E6

    0046B2AD                 mov     eax, hCursor

    0046B2B2                 push    eax             ; hCursor

    0046B2B3                 call    SetCursor

    0046B2B8                 mov     esi, eax

    0046B2BA                 xor     eax, eax

    0046B2BC                 mov     dword_4EAE50, eax

    0046B2C1                 push    0               ; int

    0046B2C3                 lea     edx, [esp+314h+arglist]

    0046B2CA                 push    edx             ; arglist

    0046B2CB                 lea     ecx, [esp+318h+path]

    0046B2CF                 push    ecx             ; path

    0046B2D0                 call    sub_469818//此函数里面主要是负责解析的函数

    0046B2D5                 add     esp, 0Ch

    0046B2D8                 call    sub_46718C

    0046B2DD                 cmp     dword_4EAE50, 0

    0046B2E4                 jnz     short loc_46B2F3

    0046B2E6

    0046B2E6 loc_46B2E6:     

    0046B2E6                 inc     ebx

    0046B2E7                 cmp     ebx, 0C8h

    0046B2ED                 jl      loc_46B268

     

     

     

    等做完上面的工作后,OD才开始真正的附加 主要是通过DebugActiveProcess对程序附加

    00478522                 mov     eax, [esi]

    00478524                 push    eax             /要附加的进程ID

    00478525                 call    DebugActiveProcess

    0047852A                 test    eax, eax

     

    之后OD按一定格式设置窗口标题;

    004785A5                 push    edx

    004785A6                 push    offset byte_4D5A7C

    004785AB                 push    offset aOllyice ; "OllyICE"

    004785B0                 push    offset aSSS_0   ; "%s - %s%s"

    004785B5                 lea     ecx, [ebp+buffer]

    004785BB                 push    ecx             ; buffer

    004785BC                 call    _sprintf

    004785C1                 add     esp, 14h

    004785C4                 lea     eax, [ebp+buffer] ; int

    004785CA                 push    eax             ; lpString

    004785CB                 mov     edx, hWnd

    004785D1                 push    edx             ; hWnd

    004785D2                 call    SetWindowTextA

    然后OD会对ollydbg.ini文件中的[History],[Arguments]两项进行设置……下面只贴出部分代码

     

    00476F08                 lea     edx, [ebx+1]

    00476F0B                 push    edx

    00476F0C                 lea     ecx, [edi+6DAh]

    00476F12                 push    ecx             ; format

    00476F13                 lea     eax, [ebp+buffer]

    00476F19                 push    eax             ; buffer

    00476F1A                 call    _sprintf

    00476F1F                 mov     edx, ebx

    00476F21                 add     esp, 0Ch

    00476F24                 shl     edx, 6

    00476F27                 lea     ecx, [ebp+var_518]

    00476F2D                 add     edx, ebx

    00476F2F                 push    offset FileName ; lpFileName

    00476F34                 shl     edx, 2

    00476F37                 lea     eax, [ebp+buffer]

    00476F3D                 add     edx, ecx

    00476F3F                 push    edx             ; lpString

    00476F40                 lea     edx, [edi+6E9h]

    00476F46                 push    eax             ; lpKeyName

    00476F47                 push    edx             ; lpAppName

    00476F48                 call    WritePrivateProfileStringA

     

     

    接着OD设置程序状态,并退出Dialog对话框

     

    0047860E                 push    0               ; name

    00478610                 push    offset byte_4D5A7C ; int

    00478615                 call    sub_409370

    0047861A                 add     esp, 8

    0047861D                 push    3  //设置状态为运行

    0047861F                 call    sub_431978

    00478624                 pop     ecx

    00478625                 push    0               ; nResult

    00478627                 push    ebx             ; hDlg

    00478628                 call    EndDialog //结束附加窗口

    0047862D                 jmp     short loc_47867B

     

     

    DebugActiveProcess附加程序后,系统会为进程中的每一个创建线程,向调试器发送CREATE_THREAD_DEBUG_EVENT调试事件,会为进程中的每个动态加载DLL向调试器发送LOAD_DLL_DEBUG_EVENT调试事件..  OD通过WaitForDebugEvent函数获得这些事件,做相应处理,并调用ContinueDebugEvent使程序继续执行…..当这些都做完后,系统恢复进程中的所有线程,并且在第一个线程恢复的时候会执行 一个 断点指令,最后会调用Ntdll.dll中的DbgBreakPoint函数 而根据跟踪得知DbgBreakPoint中的实现 就是一个int3指令;

     

    dwDebugEventCode事件处理表:

    0042EBF7                 mov     edx, DebugEvent.dwDebugEventCode

    0042EBFD                 cmp     edx, 9          ; switch 10 cases

    0042EC00                 ja      loc_4313F4      ; default

    0042EC00                                         ; jumptable 0042EC06 case 0

    0042EC06                 jmp     ds:off_42EC0D[edx*4] ; switch jump

    0042EC06 ; ---------------------------------------------------------------------------

    0042EC0D off_42EC0D      dd offset loc_4313F4    ; DATA XREF: sub_42EBD0+36r

    0042EC0D                 dd offset loc_42EC35    ; jump table for switch 

    0042EC0D                 dd offset loc_430CFF

    0042EC0D                 dd offset loc_430DD7

    0042EC0D                 dd offset loc_430F3F

    0042EC0D                 dd offset loc_431037

    0042EC0D                 dd offset loc_43112D

    0042EC0D                 dd offset loc_4311B7

    0042EC0D                 dd offset loc_431276

    0042EC0D                 dd offset loc_4313C7

     

    DbgBreakPoint的实现

     

    7C92120E >  CC              int3     

    7C92120F    C3              retn

     

    因此当程序执行到此时,会引起一个EXCEPTION_DEBUG_EVENT事件,OD通过WaitForDebugEvent函数会获得此调试事件…OD在获得EXCEPTION_DEBUG_EVENT事件后,之后并没有调用ContinueDebugEvent使程序执行。因此OD会停到DbgBreakPoint处,也就是EIP会指在retn处。

  • 相关阅读:
    Centos7 安装zabbix3.0 服务端 详细
    kubernetes 创建nginx 容器
    kubernetes 创建tomcat 容器
    kubernetes创建yaml,pod服务一直处于 ContainerCreating状态的原因查找与解决
    SpringMVC,SpringBoot利用ajax上传文件到后台
    SpringMVC,SpringBoot使用ajax传递对象集合/数组到后台
    IDEA修改显示星号*和热部署
    IDEA上的项目托管到码云步骤
    java代码块,静态代码块,静态变量,构造方法执行顺序
    java 动态绑定 多态
  • 原文地址:https://www.cnblogs.com/kuangke/p/5363180.html
Copyright © 2011-2022 走看看