Fork me on GitHub

OllyDbg使用方法


知识点

加载恶意代码:OD可以直接加载可执行文件,也可以加载DLL文件,也可以将调试器附加在进程中,我们甚至可以用命令行运行恶意代码或者执行DLL中的某个函数。

加载可执行文件:在加载可执行文件的时候OD会使用它的加载器来加载这个程序,并可在此过程选择运行的命令行参数。如果OD能确定程序的main函数就在main处中断,否则在程序PE头提供的程序入口点中断。

附加调试器到一个程序:OD在附加到一个进程时会立即暂停这个程序以及它所有的线程。

OD窗口:OD有如下几个常用窗口:

  • 反汇编窗口:这个窗口显示了被调试程序的代码,下一条要执行的指令回在窗口中高亮显示,如果项修改指令或者数据,可以在此窗口中敲击空格键。
  • 寄存器窗口:这个窗口会显示程序寄存器的当前状态,代码在调试过程中,如果莫格寄存器的值发生了改变,则此寄存器就会从黑色变成红色。右键某个寄存器选择Modify就可以修改某个寄存器中的值。
  • 栈窗口:这个窗口会显示被调试宪曾在内存中的当前状态。这个窗口总会显示给定线程得到栈顶。OD会在一些栈单元上显示一些有用的注释,这些注释描述了调用一个API之前栈中存放的参数。
  • 内存转储窗口:这个窗口显示被调试进程的实时内存转储。

内存映射:内存映射窗口显示了被调试程序的所有内存块。

基地址重定位:基地址重定位是指Windows中的一个模块没有被加载到其预定基地址时发生的情况。Windows中所有PE文件都有一个预定的基地址,它在PE文件头中称为映像基地址。大部分可执行程序都被预加载到0x00400000处,这是Windows下大多数编译器使用的默认地址,支持ALSR的程序经常被重定位。

绝对地址与相对地址:多数执行会引用内存中的相对地址,但是有些却引用内存的绝对地址。多数DLL回在PE头的.reloc节打包一个修改位置的列表。DLL的重定位会对性能造成影响,会增加加载的时间。

查看线程和堆栈:恶意代码通常使用多线程。我们在OD中可以选择View->Threads来查看线程面板窗口,这个窗口显示了线程的内存地址。由于OD时单线程的,多以我们需要暂停所有的线程,设置一个断点,继续运行程序,这样就可以保证程序在一个特定的线程内调试。

加载DLL:OD使用一个名为loaddll.exe的虚拟程序来加载DLL,然后再其主入口处暂停DLL的执行,最后单击Play按钮,运行DllMain函数,此时DllMain函数运行完毕之后选择Debug->Call DLL Export就可以调用DLL的导出函数,并调试它。

异常处理:当异常发生时,你可以通过以下热键来决定如何处理这个异常:

  • Shift+F7:进入异常
  • Shift+F8:跳过异常
  • Shift+F9:运行异常处理

分析ShellCode:OD有一种分析ShellCode的简单方法,下面是这个方法的步骤:

  • 将ShellCode从十六进制编辑器复制到剪切板
  • 再内存映射窗口中选择类型为Priv的内存区域(私有)
  • 双击这个内存窗口中的某一行,会弹出一个十六进制转储窗口,你可以检查他的内容。该区域应该包含几百个连续为0的字节。
  • 右键该区域,赋予这个区域读、写、运行的权限。
  • 返回内存转储窗口,选择刚才的内存区域将ShellCode粘贴进去。
  • 设置EIP为刚才的内存地址。
  • 完成

调试器隐藏插件:调试器隐藏插件用多种方法对探测者隐藏调试器的存在。

课后练习

Lab9-1

用OllyDbg和IDA Pro分析恶意代码文件Lab09-01.exe,回答下列问题。再第三章中我们使用基础的静态和动态分析技术,已经对这个恶意代码做了初步的分析。

问题

1.如何让这个恶意代码安装自身?

首先这道题先前在第三章分析过,但是当时还没有学习动态调试地知识,因此将本题留在了本章,根据之前静态分析地结果我们可以知道这个程序可能会因为参数地错误而进行自我删除,执行删除指令的代码如下:

我们先找到程序的主函数所在位置,这些代码会判断程序是否有参数,如果没有参数则会直接执行上图中的自我删除动作:

1
2
3
4
5
6
7
8
9
10
11
.text:00402AF0                 push    ebp
.text:00402AF1 mov ebp, esp
.text:00402AF3 mov eax, 182Ch
.text:00402AF8 call __alloca_probe
.text:00402AFD cmp [ebp+argc], 1
.text:00402B01 jnz short loc_402B1D
.text:00402B03 call sub_401000
.text:00402B08 test eax, eax
.text:00402B0A jz short loc_402B13
.text:00402B0C call sub_402360
.text:00402B11 jmp short loc_402B18

但是如果程序带有参数,程序则会进入参数判断的过程,参数字符串判断函数的完成汇编代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
.text:00402510                 push    ebp
.text:00402511 mov ebp, esp
.text:00402513 push ecx
.text:00402514 push edi
.text:00402515 mov edi, [ebp+arg_0]
.text:00402518 or ecx, 0FFFFFFFFh
.text:0040251B xor eax, eax
.text:0040251D repne scasb
.text:0040251F not ecx
.text:00402521 add ecx, 0FFFFFFFFh
.text:00402524 cmp ecx, 4
.text:00402527 jz short loc_40252D
.text:00402529 xor eax, eax
.text:0040252B jmp short loc_4025A0
.text:0040252D ; ---------------------------------------------------------------------------
.text:0040252D
.text:0040252D loc_40252D: ; CODE XREF: sub_402510+17↑j
.text:0040252D mov eax, [ebp+arg_0]
.text:00402530 mov cl, [eax]
.text:00402532 mov [ebp+var_4], cl
.text:00402535 movsx edx, [ebp+var_4]
.text:00402539 cmp edx, 61h
.text:0040253C jz short loc_402542
.text:0040253E xor eax, eax
.text:00402540 jmp short loc_4025A0
.text:00402542 ; ---------------------------------------------------------------------------
.text:00402542
.text:00402542 loc_402542: ; CODE XREF: sub_402510+2C↑j
.text:00402542 mov eax, [ebp+arg_0]
.text:00402545 mov cl, [eax+1]
.text:00402548 mov [ebp+var_4], cl
.text:0040254B mov edx, [ebp+arg_0]
.text:0040254E mov al, [ebp+var_4]
.text:00402551 sub al, [edx]
.text:00402553 mov [ebp+var_4], al
.text:00402556 movsx ecx, [ebp+var_4]
.text:0040255A cmp ecx, 1
.text:0040255D jz short loc_402563
.text:0040255F xor eax, eax
.text:00402561 jmp short loc_4025A0
.text:00402563 ; ---------------------------------------------------------------------------
.text:00402563
.text:00402563 loc_402563: ; CODE XREF: sub_402510+4D↑j
.text:00402563 mov al, [ebp+var_4]
.text:00402566 mov dl, 63h
.text:00402568 imul dl
.text:0040256A mov [ebp+var_4], al
.text:0040256D movsx eax, [ebp+var_4]
.text:00402571 mov ecx, [ebp+arg_0]
.text:00402574 movsx edx, byte ptr [ecx+2]
.text:00402578 cmp eax, edx
.text:0040257A jz short loc_402580
.text:0040257C xor eax, eax
.text:0040257E jmp short loc_4025A0
.text:00402580 ; ---------------------------------------------------------------------------
.text:00402580
.text:00402580 loc_402580: ; CODE XREF: sub_402510+6A↑j
.text:00402580 mov al, [ebp+var_4]
.text:00402583 add al, 1
.text:00402585 mov [ebp+var_4], al
.text:00402588 movsx ecx, [ebp+var_4]
.text:0040258C mov edx, [ebp+arg_0]
.text:0040258F movsx eax, byte ptr [edx+3]
.text:00402593 cmp ecx, eax
.text:00402595 jz short loc_40259B
.text:00402597 xor eax, eax
.text:00402599 jmp short loc_4025A0
.text:0040259B ; ---------------------------------------------------------------------------
.text:0040259B
.text:0040259B loc_40259B: ; CODE XREF: sub_402510+85↑j
.text:0040259B mov eax, 1
.text:004025A0
.text:004025A0 loc_4025A0: ; CODE XREF: sub_402510+1B↑j
.text:004025A0 ; sub_402510+30↑j ...
.text:004025A0 pop edi
.text:004025A1 mov esp, ebp
.text:004025A3 pop ebp
.text:004025A4 retn

为了注释以上代码,下面是我在OD中对这些代码分析的过程中的注释截图:

以上代码算是一个简单的硬编码的加密,绕了个大圈子实际上就是看参数是否为abcd

因此此程序可以通过附加参数-in abcd来进行安装。

2.这个代码的命令行选项是什么?它要求的密码是什么?

命令行选项:

命令行选项 作用
-in 安装服务
-re 卸载服务
-c 更新恶意代码配置
-cc 在控制台打印当前配置

密码是abcd

3.如何使用OllyDbg永久修补这个恶意代码,使其不需要制定的命令行密码?

只需将密码对比函数的返回值修改为1即可。

4.这个恶意代码基于系统的特征是什么?

程序创建了一个注册表。创建了一个服务%SYSTEMROOT%\system32\文件名

程序会将自身拷贝到C:\Winodows\System32\

创建注册表项HKLM\SOFTWARE\Microsoft \XPS\Configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.text:00401009                 push    eax             ; phkResult
.text:0040100A push 0F003Fh ; samDesired
.text:0040100F push 0 ; ulOptions
.text:00401011 push offset SubKey ; "SOFTWARE\\Microsoft \\XPS"
.text:00401016 push 80000002h ; hKey
.text:0040101B call ds:RegOpenKeyExA
.text:00401021 test eax, eax
.text:00401023 jz short loc_401029
.text:00401025 xor eax, eax
.text:00401027 jmp short loc_401066
.text:00401029 push 0 ; lpcbData
.text:0040102B push 0 ; lpData
.text:0040102D push 0 ; lpType
.text:0040102F push 0 ; lpReserved
.text:00401031 push offset ValueName ; "Configuration"
.text:00401036 mov ecx, [ebp+phkResult]
.text:00401039 push ecx ; hKey
.text:0040103A call ds:RegQueryValueExA

5.这个恶意代码通过网络命令执行了哪些不同的操作?

在IDA中看到了如下类似于命令的字符串:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.data:0040C098 aNothing        db 'NOTHING',0          ; DATA XREF: sub_402020:loc_402330↑o
.data:0040C098 ; sub_402020+322↑o
.data:0040C0A0 ; char aRb[]
.data:0040C0A0 aRb db 'rb',0 ; DATA XREF: sub_402020+2A1↑o
.data:0040C0A3 align 4
.data:0040C0A4 ; char asc_40C0A4[2]
.data:0040C0A4 asc_40C0A4 db '`',0 ; DATA XREF: sub_402020+28C↑o
.data:0040C0A6 align 4
.data:0040C0A8 ; char aCmd_0[4]
.data:0040C0A8 aCmd_0 db 'CMD',0 ; DATA XREF: sub_402020:loc_40223A↑o
.data:0040C0A8 ; sub_402020+22C↑o
.data:0040C0AC ; char aDownload[]
.data:0040C0AC aDownload db 'DOWNLOAD',0 ; DATA XREF: sub_402020:loc_402186↑o
.data:0040C0AC ; sub_402020+178↑o
.data:0040C0B5 align 4
.data:0040C0B8 ; char aUpload[]
.data:0040C0B8 aUpload db 'UPLOAD',0 ; DATA XREF: sub_402020:loc_4020D2↑o
.data:0040C0B8 ; sub_402020+C4↑o
.data:0040C0BF align 10h
.data:0040C0C0 ; char asc_40C0C0[]
.data:0040C0C0 asc_40C0C0 db ' ',0 ; DATA XREF: sub_402020+56↑o
.data:0040C0C0 ; sub_402020+70↑o ...
.data:0040C0C2 align 4
.data:0040C0C4 ; char aSleep[]
.data:0040C0C4 aSleep db 'SLEEP',0 ; DATA XREF: sub_402020:loc_40204C↑o
.data:0040C0C4 ; sub_402020+3E↑o

通过查看这些字符串的引用位置,可以得出如下结论:

命令 功能
NOTHING 字符串比对完成后不执行任何操作
DOWNLOAD 读取本地文件并发送到远程主机
UPLOAD c从一个网络位置下载文件到本地
CMD 通过进程API和网络API打开一个远程的shell
SLEEP 休眠

6.这个恶意代码是否有网络特征?

恶意代码向http://www.practicalmalwareanalysis.com发出一个http的请求

Lab9-2

用OllyDbg分析恶意代码文件Lab09-02.exe,回答下列问题。

问题

1.在二进制文件中,你看到的静态字符串是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.rdata:004040CC	0000000F	C	runtime error 
.rdata:004040E0 0000000E C TLOSS error\r\n
.rdata:004040F0 0000000D C SING error\r\n
.rdata:00404100 0000000F C DOMAIN error\r\n
.rdata:00404110 00000025 C R6028\r\n- unable to initialize heap\r\n
.rdata:00404138 00000035 C R6027\r\n- not enough space for lowio initialization\r\n
.rdata:00404170 00000035 C R6026\r\n- not enough space for stdio initialization\r\n
.rdata:004041A8 00000026 C R6025\r\n- pure virtual function call\r\n
.rdata:004041D0 00000035 C R6024\r\n- not enough space for _onexit/atexit table\r\n
.rdata:00404208 00000029 C R6019\r\n- unable to open console device\r\n
.rdata:00404234 00000021 C R6018\r\n- unexpected heap error\r\n
.rdata:00404258 0000002D C R6017\r\n- unexpected multithread lock error\r\n
.rdata:00404288 0000002C C R6016\r\n- not enough space for thread data\r\n
.rdata:004042B4 00000021 C \r\nabnormal program termination\r\n
.rdata:004042D8 0000002C C R6009\r\n- not enough space for environment\r\n
.rdata:00404304 0000002A C R6008\r\n- not enough space for arguments\r\n
.rdata:00404330 00000025 C R6002\r\n- floating point not loaded\r\n
.rdata:00404358 00000025 C Microsoft Visual C++ Runtime Library
.rdata:00404384 0000001A C Runtime Error!\n\nProgram:
.rdata:004043A4 00000017 C <program name unknown>
.rdata:004043BC 00000013 C GetLastActivePopup
.rdata:004043D0 00000010 C GetActiveWindow
.rdata:004043E0 0000000C C MessageBoxA
.rdata:004043EC 0000000B C user32.dll
.rdata:00404562 0000000D C KERNEL32.dll
.rdata:0040457E 0000000B C WS2_32.dll

2.当你运行这个二进制文件,会发生什么?

好像并没有发生什么。。。

3.怎样让恶意代码的攻击负载获得运行?

看到如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.text:00401205                 push    eax             ; lpFilename
.text:00401206 push 0 ; hModule
.text:00401208 call ds:GetModuleFileNameA
.text:0040120E push 5Ch ; int
.text:00401210 lea ecx, [ebp+Filename]
.text:00401216 push ecx ; char *
.text:00401217 call _strrchr
.text:0040121C add esp, 8
.text:0040121F mov [ebp+var_4], eax
.text:00401222 mov edx, [ebp+var_4]
.text:00401225 add edx, 1
.text:00401228 mov [ebp+var_4], edx
.text:0040122B mov eax, [ebp+var_4]
.text:0040122E push eax ; char *
.text:0040122F lea ecx, [ebp+var_1A0]
.text:00401235 push ecx ; char *
.text:00401236 call _strcmp
.text:0040123B add esp, 8
.text:0040123E test eax, eax
.text:00401240 jz short loc_40124C
.text:00401242 mov eax, 1
.text:00401247 jmp loc_4013D6

用于字符串比较的函数的两个参数一个是此程序的文件名,另一个是ocl.exe

如果文件名不是ocl.exe的话程序会直接退出,因此我们需要将文件名修改为ocl.exe

4.在地址0x00401133处发生了什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
v13 = '1';
v14 = 'q';
v15 = 'a';
v16 = 'z';
v17 = '2';
v18 = 'w';
v19 = 's';
v20 = 'x';
v21 = '3';
v22 = 'e';
v23 = 'd';
v24 = 'c';
v25 = '\0';
v26 = 'o';
v27 = 'c';
v28 = 'l';
v29 = '.';
v30 = 'e';
v31 = 'x';
v32 = 'e';
v33 = '\0';

在这个位置上可以发现两个字符串:1qaz2wsx3edcocl.exe,但是IDA没有自动识别出这个字符串,因为这些字符是在栈中的。

5.传递给子例程0x00401089的参数是什么?

1qaz2wsx3edc和一个位于00405034长度21h的数据缓冲区

6.恶意代码使用的域名是什么?

把断点下在加密函数的rten语句之后可以看到返回值如下:

www.practicalmalwareanalysis.com

7.恶意代码使用什么编码函数来混淆域名?

通过对0x00401089函数的分析,此函数将1qaz2wsx3edci循环取余的结果作了异或操作。

8.恶意代码在0x0040106E处调用CreateProcessA函数的意义是什么?

通过查看此位置函数的参数,发现最后一个参数是一个SOCKET对象,函数将这个SOCKET对象作为CreateProcess函数的StartupInfo的标准输入、标准输出和标准错误,用这个方式来实现了一个反向连接的shell。

Lab9-3

使用OD和IDA分析此恶意代码时。这个恶意代码加载的三个自带的DLL,他们在编译时请求相同的内存加载位置,因此,在OD中对照IDA浏览这些DLL可以发现,相同的代码可能会出现在不同的内存位置。这个实验的目的是让你使用OD看代码时可以轻松和地在IDA中找到它对应的位置。

问题

1.Lab09-03.exe导入了哪些DLL?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Address	Ordinal	Name	Library
00405000 DLL1Print DLL1
00405008 DLL2ReturnJ DLL2
0040500C DLL2Print DLL2
00405014 WriteFile KERNEL32
00405018 LCMapStringW KERNEL32
0040501C CloseHandle KERNEL32
00405020 LoadLibraryA KERNEL32
00405024 GetProcAddress KERNEL32
00405028 GetStringTypeA KERNEL32
0040502C Sleep KERNEL32
00405030 GetCommandLineA KERNEL32
00405034 GetVersion KERNEL32
00405038 ExitProcess KERNEL32
0040503C TerminateProcess KERNEL32
00405040 GetCurrentProcess KERNEL32
00405044 UnhandledExceptionFilter KERNEL32
00405048 GetModuleFileNameA KERNEL32
0040504C FreeEnvironmentStringsA KERNEL32
00405050 FreeEnvironmentStringsW KERNEL32
00405054 WideCharToMultiByte KERNEL32
00405058 GetEnvironmentStrings KERNEL32
0040505C GetEnvironmentStringsW KERNEL32
00405060 SetHandleCount KERNEL32
00405064 GetStdHandle KERNEL32
00405068 GetFileType KERNEL32
0040506C GetStartupInfoA KERNEL32
00405070 GetModuleHandleA KERNEL32
00405074 GetEnvironmentVariableA KERNEL32
00405078 GetVersionExA KERNEL32
0040507C HeapDestroy KERNEL32
00405080 HeapCreate KERNEL32
00405084 VirtualFree KERNEL32
00405088 HeapFree KERNEL32
0040508C RtlUnwind KERNEL32
00405090 HeapAlloc KERNEL32
00405094 GetCPInfo KERNEL32
00405098 GetACP KERNEL32
0040509C GetOEMCP KERNEL32
004050A0 VirtualAlloc KERNEL32
004050A4 HeapReAlloc KERNEL32
004050A8 MultiByteToWideChar KERNEL32
004050AC LCMapStringA KERNEL32
004050B0 GetStringTypeW KERNEL32
004050B8 NetScheduleJobAdd NETAPI32

2.DLL1.dll、DLL2.dll、DLL3.dll要求的基地址是多少?

在PE Explorer中分别查看这三个程序的额映像基地址:

  • DLL1:10000000h
  • DLL2:10000000h
  • DLL3:10000000h

3.当使用OD调试Lab09-03.exe时,为DLL1.dll、DLL2.dll、DLL3.dll分配的基地址是什么?

如图三个程序的基地址分别为:100000000003000000A50000

4.当Lab09-03.exe调用DLL1.dll中的一个导入函数时,这个导入函数都做了什么?

进入此函数发现:

通过查看DLL1.10008034的交叉引用发现这个值等于GetCurrentProcessId()的返回值。

5.当Lab09-03.exe调用WriteFile函数时,它写入的函数名是什么?

第一处:

1
2
3
4
5
6
7
8
9
10
11
12
.text:00401006                 call    ds:DLL1Print
.text:0040100C call ds:DLL2Print
.text:00401012 call ds:DLL2ReturnJ
.text:00401018 mov [ebp+hFile], eax
.text:0040101B push 0 ; lpOverlapped
.text:0040101D lea eax, [ebp+NumberOfBytesWritten]
.text:00401020 push eax ; lpNumberOfBytesWritten
.text:00401021 push 17h ; nNumberOfBytesToWrite
.text:00401023 push offset aMalwareanalysi ; "malwareanalysisbook.com"
.text:00401028 mov ecx, [ebp+hFile]
.text:0040102B push ecx ; hFile
.text:0040102C call ds:WriteFile

可以看到程序员的参数是DLL2ReturnJ的返回值,因此进入DLL2中看到参数是一个对0x1000B078的访问,在OD中在此位置下一个访问断点,运行之后看到如下结果:

因此得知此文件是temp.txt

6.当Lab09-03.exe使用NetScheduleJobAdd函数创建一个job时,从哪里获取第二个参数的数据?

在OD中看到Lab09-03.exeNetScheduleJobAdd的第二个参数来自于DLL3的00B5B0A0,DLL3的基地址是00B50000,因此对应到DLL3中就是B050的位置,在DLL3中发现:

1
.text:10001066                 mov     dword ptr [eax], offset dword_1000B0A0

7.在运行或调试Lab09-03.exe时,你会看到Lab09-03.exe打印出三块神秘数据。DLL1的神秘数据、DLL2的神秘数据、DLL3的神秘数据分别是什么?

DLL1:上面分析过了是当前进程的ID。

DLL2:temp.txt

1
2
3
push    offset FileName ; "temp.txt"
call ds:CreateFileA
mov dword_1000B078, eax

DLL3:ping www.malwareanalysisbook.com

1
2
3
4
5
6
7
8
9
.text:10001004                 mov     [ebp+lpMultiByteStr], offset aPingWwwMalware ; "ping www.malwareanalysisbook.com"
.text:1000100B push 32h ; cchWideChar
.text:1000100D push offset WideCharStr ; lpWideCharStr
.text:10001012 push 0FFFFFFFFh ; cbMultiByte
.text:10001014 mov eax, [ebp+lpMultiByteStr]
.text:10001017 push eax ; lpMultiByteStr
.text:10001018 push 0 ; dwFlags
.text:1000101A push 0 ; CodePage
.text:1000101C call ds:MultiByteToWideChar

8.如何将DLL2.dll加载到IDA Pro中,使得他与OD的加载地址匹配?

选择手动加载:

在弹出的窗口中设置新的基地址即可:

本章结束🎊

您的支持是我最大的动力🍉