知识点 加载恶意代码: 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:004040 CC 0000000 F C runtime error .rdata:004040E0 0000000 E C TLOSS error\r\n .rdata:004040F0 0000000 D C SING error\r\n .rdata:00404100 0000000 F 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 0000002 D C R6017\r\n- unexpected multithread lock error\r\n .rdata:00404288 0000002 C C R6016\r\n- not enough space for thread data\r\n .rdata:004042B4 00000021 C \r\nabnormal program termination\r\n .rdata:004042D8 0000002 C C R6009\r\n- not enough space for environment\r\n .rdata:00404304 0000002 A 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 0000001 A C Runtime Error!\n\nProgram: .rdata:004043A4 00000017 C <program name unknown> .rdata:004043 BC 00000013 C GetLastActivePopup .rdata:004043D0 00000010 C GetActiveWindow .rdata:004043E0 0000000 C C MessageBoxA .rdata:004043 EC 0000000 B C user32.dll .rdata:00404562 0000000 D C KERNEL32.dll .rdata:0040457 E 0000000 B 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' ;
在这个位置上可以发现两个字符串:1qaz2wsx3edc
、ocl.exe
,但是IDA没有自动识别出这个字符串,因为这些字符是在栈中的。
5.传递给子例程0x00401089的参数是什么?
1qaz2wsx3edc
和一个位于00405034
长度21h
的数据缓冲区
6.恶意代码使用的域名是什么? 、
把断点下在加密函数的rten语句之后可以看到返回值如下:
www.practicalmalwareanalysis.com
7.恶意代码使用什么编码函数来混淆域名?
通过对0x00401089
函数的分析,此函数将1qaz2wsx3edc
与i
循环取余的结果作了异或操作。
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 Library00405000 DLL1Print DLL100405008 DLL2ReturnJ DLL20040500 C DLL2Print DLL200405014 WriteFile KERNEL3200405018 LCMapStringW KERNEL320040501 C CloseHandle KERNEL3200405020 LoadLibraryA KERNEL3200405024 GetProcAddress KERNEL3200405028 GetStringTypeA KERNEL320040502 C Sleep KERNEL3200405030 GetCommandLineA KERNEL3200405034 GetVersion KERNEL3200405038 ExitProcess KERNEL320040503 C TerminateProcess KERNEL3200405040 GetCurrentProcess KERNEL3200405044 UnhandledExceptionFilter KERNEL3200405048 GetModuleFileNameA KERNEL320040504 C FreeEnvironmentStringsA KERNEL3200405050 FreeEnvironmentStringsW KERNEL3200405054 WideCharToMultiByte KERNEL3200405058 GetEnvironmentStrings KERNEL320040505 C GetEnvironmentStringsW KERNEL3200405060 SetHandleCount KERNEL3200405064 GetStdHandle KERNEL3200405068 GetFileType KERNEL320040506 C GetStartupInfoA KERNEL3200405070 GetModuleHandleA KERNEL3200405074 GetEnvironmentVariableA KERNEL3200405078 GetVersionExA KERNEL320040507 C HeapDestroy KERNEL3200405080 HeapCreate KERNEL3200405084 VirtualFree KERNEL3200405088 HeapFree KERNEL320040508 C RtlUnwind KERNEL3200405090 HeapAlloc KERNEL3200405094 GetCPInfo KERNEL3200405098 GetACP KERNEL320040509 C GetOEMCP KERNEL32004050 A0 VirtualAlloc KERNEL32004050 A4 HeapReAlloc KERNEL32004050 A8 MultiByteToWideChar KERNEL32004050 AC LCMapStringA KERNEL32004050B 0 GetStringTypeW KERNEL32004050B 8 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分配的基地址是什么?
如图三个程序的基地址分别为:10000000
、00030000
、00A50000
。
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.exe
中NetScheduleJobAdd
的第二个参数来自于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的加载地址匹配?
选择手动加载:
在弹出的窗口中设置新的基地址即可:
本章结束🎊