恶意代码 实验三1,3 PE文件病毒感染与恢复

1.分析感染后的可执行程序

(1)确定感染后程序包含哪几个节,每个节的访问属性如何;

访问属性参考文档

来源于PE Explorer的帮助文档

The last member of a section header is the 32 bits 'Characteristics', which is a bunch of flags describing how the section's memory should be treated:

If bit 5 (IMAGE_SCN_CNT_CODE) is set, the section contains executable code.

If bit 6 (IMAGE_SCN_CNT_INITIALIZED_DATA) is set, the section contains data that gets a defined value before execution starts. In other words: the section's data in the file is meaningful.

If bit 7 (IMAGE_SCN_CNT_UNINITIALIZED_DATA) is set, this section's data is uninitialized data and will be initialized to all-0-bytes before execution starts. This is normally the BSS.

If bit 9 (IMAGE_SCN_LNK_INFO) is set, the section doesn't contain image data but comments, description or other documentation.

If bit 11 (IMAGE_SCN_LNK_REMOVE) is set, the data is part of an object file's section that is supposed to be left out when the executable file is linked.

If bit 12 (IMAGE_SCN_LNK_COMDAT) is set, the section contains "common block data", which are packaged functions of some sort.

Bit 15 (IMAGE_SCN_MEM_FARDATA) is reserved for future use.

Bit 17 (IMAGE_SCN_MEM_PURGEABLE) is reserved for future use.

The same is IMAGE_SCN_MEM_16BIT.

Bit 18 (IMAGE_SCN_MEM_LOCKED) is reserved for future use.

Bit 19 (IMAGE_SCN_MEM_PRELOAD) is reserved for future use.

Bits 20 to 23 specify an alignment of data on a 1/8192-byte boundary. This is valid for object files only.

Bit 24 (IMAGE_SCN_LNK_NRELOC_OVFL) indicates that the count of relocations for the section exceeds the 16 bits reserved for it in section header. If the bit is set and the NumberOfRelocations field in the section header is 0xffff, the actual relocation count is stored in the 32-bit VirtualAddress field of the first relocation.

If bit 25 (IMAGE_SCN_MEM_DISCARDABLE) is set, the section's data is not needed after the process has started. This is the case, for example, with the relocation information. I've seen it also for startup routines of drivers and services that are only executed once.

If bit 26 (IMAGE_SCN_MEM_NOT_CACHED) is set, the section's data should not be cached. Don't ask my why not. Does this mean to switch off the 2nd-level-cache?

If bit 27 (IMAGE_SCN_MEM_NOT_PAGED) is set, the section's data should not be paged out. This may be interesting for drivers.

If bit 28 (IMAGE_SCN_MEM_SHARED) is set, the section's data is shared among all running instances of the image. If it is e.g. the initialized data of a DLL, all running instances of the DLL will at any time have the same variable contents.
Note that only the first instance's section is initialized. Sections containing code are always shared.

If bit 29 (IMAGE_SCN_MEM_EXECUTE) is set, the process gets 'execute'-access to the section's memory.

If bit 30 (IMAGE_SCN_MEM_READ) is set, the process gets 'read'-access to the section's memory.

If bit 31 (IMAGE_SCN_MEM_WRITE) is set, the process gets 'write'-access to the section's memory.

--------------

After the section headers we find the sections themselves. They are, in the file, aligned to 'FileAlignment' bytes (that is, after the optional header and after each section's data there will be padding bytes). When loaded (in RAM), the sections are aligned to 'SectionAlignment' bytes.

As an example, if the optional header ends at file offset 981 and 'FileAlignment' is 512, the first section will start at byte 1024. Note that you can find the sections via the 'PointerToRawData' or the 'VirtualAddress', so there is hardly any need to actually fuss around with the alignments.

The remainder of an image file contains blocks of data that are not necessarily at any specific file offset. Instead the locations are defined by pointers in the Optional Header or a section header. An exception is for images with a Section Alignment value (see the Optional Header description) of less than the page size of the architecture (4K for Intel x86 and for MIPS; 8K for Alpha). In this case there are constraints on the file offset of the section data. Another exception is that attribute certificate and debug information must be placed at the very end of an image file (with the attribute certificate table immediately preceding the debug section), because the loader does not map these into memory. The rule on attribute certificate and debug information does not apply to object files, however.

原本的弹窗程序test.exe被感染后

image-20210508111631026

image-20210508111701730

image-20210508111755707

image-20210508111822974

原本的记事本程序重命名为test.exe并被感染后

image-20210508112035356

image-20210508112100097

image-20210508112131942

image-20210508112207455

原本的计算器程序重命名为test.exe并被感染后

image-20210508112336663

image-20210508112354218

image-20210508112419215

image-20210508112450994

(2)这两方面与感染前程序相比,有什么变化

原本的弹窗程序test.exe被感染前

image-20210508112819613

image-20210508112842043

image-20210508112913453

原本的记事本程序notepad.exe被感染前

image-20210508113034143

image-20210508113051129

image-20210508113115072

原本的计算器程序calc.exe被感染前

image-20210511220704458

image-20210511220739565

image-20210511220906182

分析发现,不管是哪个文件,文件被感染后比被感染前多出了一个.hum节,其访问属性是IMAGE_SCN_CNT_CODE(节中包含可执行的代码)、IMAGE_SCN_MEM_EXECUTE(进程对节的内存有执行权限)、IMAGE_SCN_MEM_READ(进程对节的内存有读权限)、IMAGE_SCN_MEM_WRITE(进程对节的内存有写内存)。而感染前本来就有的节没有发生变化。

(3)判断“病毒”程序是否会反复感染同一文件;如果可以,多次感染和一次感染的不同点是什么;如果不可以,那么“病毒” 程序如何做到不重复感染

“病毒”程序不可以反复感染同一文件。

test.exe已经被感染后尝试再次运行病毒程序,提示没有再次感染。

image-20210512065747901

GetApiA部分代码的调试

用ollydbg调试,F7单步执行,步入GetApiA

image-20210512005951647

GetApiA中调用另外一个过程

image-20210512010159449

发现程序死循环在这个过程里面

image-20210511225910756

查资料后发现这并不是死循环,而是当每次循环使计数器减一,当计数器值为0时跳出循环。此处loop使用的计数器是寄存器ECX,而通过寄存器EAX查找目标函数,根据堆栈和ESI,猜测要寻找的是GetModuleHandleA函数。根据cmp bl,byte ptr ds:[edx+eax] je short 感染程序.00401016完成判断跳出循环。

image-20210511231435410

用depends打开一个exe,查看user32.dll中的函数,发现GetModuleHandleA的编号是177。

image-20210511233801668

此时找到GetModuleHandleA

image-20210511233329683

一个字符一个字符地进行比较,把相同的位数存到EDX中

image-20210511233529904

发现之后又使用这个循环去寻找其他函数,那么直接用F8跳过找函数的call 40100A这部分代码即可。注意到其在查找GetModuleHandleA之后又寻找了GetProcAddressLoadLibraryACreateFileACreatingFileMappingAMapViewOfFileUnmapViewOfFileCloseHandleGetFileSizeSetFilePointerSetEndOfFileExitProcess这些函数。

image-20210511234352987

my_infect部分代码的调试

跳转到40144D处,F2下断点,F9运行至断点处,步入my_infect部分的代码

image-20210512000900556

经过call [ebp+aCreateFile]inc eax后,EAX的值不为0,ZF值为0,所以je _Err不会进行跳转,说明打开目标文件test.exe成功。

image-20210512002042687

同理,后面的得到文件大小、关闭文件、创建文件映射、映射文件也都成功,my_include部分代码顺利执行完毕。

modipe.asm部分代码的调试

my_include部分执行结束后,紧接着的是modipe.asm

image-20210512003241690

image-20210512003152740

执行cmp word ptr [esi],'ZM'后,ZF为1,所以jne CouldNotInfect不跳转。

image-20210512003950663

执行cmp word ptr [esi],'EP'后,ZF为1,所以jne CouldNotInfect不跳转

image-20210512003455143

执行cmp dword ptr [esi+8],'dark'后,ZF为1,所以je CouldNotInfect跳转。也就是说,因为文件中已经存在了dark这个感染标记,所以不再次感染此文件。

image-20210512004047972

CouldNotInfect部分代码的调试

image-20210512004323196

执行test eax,eax后,ZF为0,所以jnz @g12不跳转

image-20210512004411222

然后会依次call No captioncall _tips

_tips部分代码的调试

image-20210512004840570

这里调用MessageBoxA函数,弹出弹窗“本程序仅感染本目录下未被感染过的test.exe程序。”

image-20210512004948783

_where部分代码的调试

image-20210512005115201

执行cmp dword ptr [esi+8],'dark'后,ZF为0,判断出是启动程序而不是HOST程序,所以je jmp_oep不跳转

image-20210512005319476

然后jmp _xit跳转到_xit

_xit部分的代码调试

image-20210512005538186

退出启动程序。

2.分析源程序main.asm

(1)定位并分析其中重定位相关的代码,说明存储相应偏差位移量的寄存器是哪个;

(2)定位并分析其中获取kernel32.dll在内存中装载位置的代码,说明记录装载位置的存储单元(包含寄存器和变量)

3.手工清除被感染程序中的“病毒”部分,将感染程序尽可能还原为原正常的程序,同时达到免疫效果

用winhex和PEview恢复文件并实现免疫

用winhex打开一个被感染后和一个被感染前的test.exe,进行对比,同时借助PEview理解PE文件格式。

image-20210512060422197

B6处的节数修改为原来的3

image-20210512061757231

image-20210512061830066

B8处的感染标记"dark"不要删除,这是使test.exe免疫此实验中的病毒所要利用的。

image-20210512061026678

D8处的入口点地址需要修改为原来的1000

image-20210512060959836

image-20210512061253054

100处的Image大小修改为原来的4000

image-20210512061451036

image-20210512061545509

220248的.hum的IMAGE_SECTION_HEADER清0

image-20210512062231813

image-20210512062403136

A00到最后的.hum节清零

image-20210512062531281

image-20210512062846777

A00到最后的.hum节删掉,把文件恢复至原来大小

使用winhex的选块选择这部分

image-20210512063228021

鼠标右键→编辑→移除

image-20210512063330226

发现剩下了近一行,继续移除

image-20210512063434128

至此文件恢复完毕

image-20210512063451477

保存恢复后的文件为test_Rev.exe,发现其大小已经变为被感染前的2560字节,而不再是被感染后的6656字节。

image-20210512063724479

比较恢复后和被感染前的文件

在linux中使用xxd指令将二进制文件转为16进制文本文件

xxd test_Rev.exe > test_Rev.txt

xxd test.exe > test.txt

然后用vscode比较两个文本文件的不同

image-20210512065102517

image-20210512065124380

比较发现,两个文件唯一不同的地方就在于test_Rev.exe具有"dark"这个感染标记,则确定已经尽可能将文件恢复为感染前的样子

image-20210512065222461

运行测试结果

运行test_Rev.exe,可以实现与被感染前的test.exe一样的效果

image-20210512065409833

image-20210512065422068

test_Rev.exe重命名为test.exe,放到与病毒文件同一个文件夹中,尝试用病毒文件感染它

image-20210512065546078

提示无法感染

再次运行test.exe,发现确实没有被感染

image-20210512065619113

image-20210512065631552

posted @ 2021-05-12 07:00  平静的雨田  阅读(1166)  评论(1编辑  收藏  举报