博客: https://qwer597.github.io/
ApplicationName作为存放进程路径的对象传入sub_40149D
用GetSystemDirectoryA获取进程路径并拼接,得到系统程序svchost.exe的路径
Findresource(确定指定模块中指定类型和名称的资源所在位置)
确定UNICODE和LOCALIZATION坐在被加密资源区的首地址
这里的hModule就是当前程序的句柄
发现这段数据被加密,且类型和名称都符合反汇编的
这里标注红色的call将资源节内的数据存放在VirtualAlloc开辟的空间内
之后检查PE文件标志,确定文件完好接下来在loc_40141B中调用sub_401000传入密码 ’41H’
sub_401000是对前文所说的加密资源节进行解密,
这里的Xor不是习惯的寄存器清空操作 在ida动态调试时候,此处xor是逐字节解密
此函数是进程替换的核心函数
检测DOS头标志‘MZ’,NT头标志’PE’两个标志位分别是DOS段和NT段的首地址
在下文中对pe文件内数据读取的操作起到重要作用
通过creatprocessA创建exe文件的线程并挂起,起始位置是0001
接着在0000位置创建长度为2CC的空间
GetThreadContext获得线程的上下文
本程序中在进程被挂起时候ebx保存进程环境块(PEB)的首地址
在context基础上+0xA4就是ebx
对进程内存操作时候需要进程处于挂起状态
线程Context结构体是记录线程某时刻所有寄存器的状态,就也就是上下文
添加context结构体,方便分析
在ida中添加context结构体后就可以对0xA4替换,发现ida自动识别为context结构体下的ebx寄存器
下一行指令加8就是在pcb上做偏移,这个位置是进程内存的虚拟内存位置
ReadProcessMemory函数将进程内存的内容存放到Buffer指向的位置(NtUnmapViewOfSection的参数)
此时buffer内容被更新为进程内存的虚拟内存位置
GetModuleHandleA和GetProcAddress通常一起使用,在指定的windows函数库中调用指定的函数
此程序中在ntdll.dll中调用NtUnmapViewOfSection函数 ,NtUnmapViewOfSection的指针作为存在var_18里
NtUnmapViewOfSection将Buffer的内容与参数中的进程的内存进行匹配,如果相同,删除进程内存
[ebp+var_64]调用 NtUnmapViewOfSection
删除内存后用VirtualAllocEx开辟新内存,这里var_8是pe文件的起始位置
+50h的偏移读取的数据是pe文件内存镜像的总尺寸
+34h是映像基址
这个位置将来放一个完整的pe文件
WriteProcessMemory将IpBuffer内容复制到进程中
+54h的偏移是DOS和PE和区段总长度
也就是说将一个完整的pe文件写入上个函数开辟的空间
之前已经判断出var_8是NT头首地址,所以可以再ida中添加NT结构体,ida会自动识别偏移在结构体中的位置
接着是一个循环,var_70是循环的次数var_8+6的偏移是pe文件区段数
下一步是对区块进行复制
区段是连续存放在pe文件中,且长度是28h
存放区段的首地址是NT头+f8h的偏移,也就是NT头长度是F8h
+10h是区段头的偏移,表示区段在文件中的大小
+14h表示区段在文件中的偏移
+0ch表示区段载入物理内存后的虚拟地址
所以每次循环将解密后的文件内容以区段的形式写入进程内存中
将解密后文件NT头的映像及地址写入进程的虚拟地址中,也就是让线程入口点改到解密后文件的oep,读取起始位置发生改变也是进程替换的步骤之一
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2022-12-13 10:58
被wx_好一脚头球编辑
,原因: