浅谈IAT加密原理及过程
上一次做完代码段加密后,又接触到了新的加密方式:IAT加密
IAT加密是通过隐藏程序的导入表信息,以达到增加分析程序的难度。因为没有导入表,就无法单纯的从静态状态下分析调用了什么函数,动态调试时,也无法直接从调用处判断出调用的函数。从而增加了程序分析的难度。
IAT加密思路如下:
1.把IAT信息全部删除掉,只留下DLL名和第一个调用函数的信息(目的是让程序在最开始运行时能正常调用那些初始化类的函数)
2.根据导入表的信息,自己实现函数加载,通过LoadLibraryA和GetProcAddress函数把DLL中的所有函数加载进来,并在程序中保存加载后的函数地址。(但由于是用程序A给程序B加密,程序B未运行时,如何获得这2个函数的地址呢?而且IAT表也已经被删掉了。此时只能借助PEB和TEB来获取这2个函数的地址,并记录在程序B中,当程序B运行时,就可以通过对应的位置取得函数地址)
3.找到所有 “指令中包含了IAT加载地址” 的指令,并记录这些指令的位置(指令所在位置而不是指令中的地址位置)
4.构建一个shellcode表,里面写着每个3.里所找到的指令的处理代码,简单来说就是把3.所找到的地址,修改成跳到4的这个shellcode表对应的处理指令中,这段处理指令实现和3.的指令一样的效果。
5.把3.中的指令修改为一个jmp,jmp到4.中对应的处理代码。实现一样的效果。
6.把重定位表中,有关于IAT表的项删掉,因为IAT加密后,原调用位置的指令是跳转到自己写的shellcode中,里面的指令是在函数运行后修改的。无需重定位了。
实现步骤:
1.先常规的检查该程序是否为PE文件(检查"MZ"和“PE”是否存在)
2.通过导入表,找到对应的IAT值,并构建一个向量vector用于存储。(注:这里为IAT的值,而不是IAT的值指向的地址中的值)
3.根据2.中所找到的IAT,找到在源文件中,又那些是使用了这个值的,分别是mov exx(每个寄存器对应的二进制数不同),push,call,jmp。记得这里记录的是调用指令的位置,而不是调用指令中IAT地址所在的位置
4.用向量vector+结构体的方式先将IAT表中的信息保存下来(DLL个数,每个DLL的名及名字的长度。这个DLL是通过什么方式导出函数(名称/序号);DLL有几个导出函数,他们分别的值是多少,如果他是以名称导出的话,该名称的长度和值分别又是多少)。
5.接着隐藏被加密文件的导入表,每个DLL下面的INT和IAT表只保留第一个值,其他的全部赋值为0,去除掉导入信息
6.更新重定位表数据,如果没有重定位表则跳过这项。看7.
6.1先把重定位表的值保存下来,以便后续移动到程序末尾(这么做的目的是为了后续添加新的重定位项时,重定位块的范围能覆盖上) (例:当前程序最大内存偏移为0x15000,增加后的偏移为0x18000,如果不把重定位移到最后的话,新增加的这0x3000中就无法被重定位到)
6.2把目标程序的重定位表数据清空
7.将每个节的保护属性修改为可写(本来只修改.text节的属性即可,但由于该节的位置不在data数组里面记录,单凭节名判断未必准确,所以将所以节都改为可写)
8.创建一个新的节,把4中保存的导入表信息填充进去。由于已知这些信息的长度,写shellcode时把位置一一对应即可。
8.1再在这个节当中,申请导入函数个数*4的空间,以便存放后续导入的函数地址
8.2记录当前的内存地址,设为新的OEP;
8.3最为重要的一点:编写shellcode
8.3.1:由于LoadLibraryA和GetProcAddress都为Kernel32中的导出函数;所以先通过进程的fs:[0x30]获取到PEB结构,再在该结构的0x0C的位置获取到该进程的DLL列表指针,再通过这个列表的0x1C的位置获取初始化模块列表;通过这个初始化模块列表取得结构,对比结构成员中的长度和值,取到目标DLL(Kernel32.dll)在该程序的装载基址
8.3.2获得Kernel32的装载基址后,把该地址当成一个PE文件处理,通过偏移取值,最后找到导出表位置,根据导出表中的数据一一比对,得到LoadLibraryA和GetProcAddress在该程序的位置。保存起来
8.3.3根据8中保存的导入表数据,一一调用LoadLibraryA获得目标DLL的装载地址,再根据该装载地址,调用GetProcAddress把其中的函数地址全部获取出来,并按导入表的顺序,保存到8.1所预留出来的空间中
8.3.4构造代替原导入表功能的shellcode块,每个shellcode块对应一个使用到IAT地址的位置(2.所保存的值)。
8.3.5把原调用到IAT指令的位置,全部修改为jmp到8.3.4对应的shellcode块,注意指令长度,替换后的指令为jmp [目标shellcode块地址],占5字节,如原指令占6字节的话,填充一个nop对齐 流程为:找到调用IAT地址的指令位置(3.中保存了),将其替换成jmp [对应shellcode块地址],在对应shellcode块中,把自己在8.3.3所获得的函数地址,用混淆的方式,实现成原来的功能。(本来为mov eax [iat地址],修改成JMP 对应shellcode块,对应shellcode块里实现mov eax [自己所获得的函数地址])
9.如果没有重定位表跳过这一步,看10. 把重定位把重定位表中有关调用函数的指令位置删掉(注:这里的位置为指令当中的地址的位置,例:E9 0X0123 4567在0x8的位置,那么地址位置就为0x9)。这么做的目的是因为IAT表加密后,函数都是自己实现导入的,原导入表的这些项无需再进行重定位了,填充时地址就已经是当前程序的位置了。
10.由于8.3.4的shellcode块中需要用到基址,这里利用了重定位表的方式获得基址,所以要把每个shellcode块中,对应获得基址的指令地址也添加到重定位块中
11.将新增的节按文件对齐和内存对齐后,将重定位表恢复,恢复起始位置为新增节的起始位置+对齐后的大小
11.IAT加密完成
下面附上代码:代码长度1594 未精简,有备注
1 #include<iostream>
2 #include<Windows.h>
3 #include<map>
4 #include<vector>
5 #include "Asmjit\\asmjit.h"
6
7 using namespace std;
8 using namespace asmjit;
9 using namespace asmjit::x86;
10
11 int g_iFileSize = 0; //文件大小
12 UCHAR *g_pFileSrc = NULL; //文件内容 (此处必须为无符号字符指针,因为char会将十六进制的最高位默认为符号位)
13 int g_iSectionAlignment = 0;//内存对齐大小
14 int g_iFileAlignment = 0;//文件对齐大小
15 int g_iImageBase = 0;//程序基址
16 int g_iNewOEP = 0;//新入口点
17 int g_iOldOEP = 0;//旧入口点
18
19 struct FuncTag
20 {
21 BYTE iFuncNameLenth;//函数名称长度
22 char *szFuncName;
23 };
24 struct DLLFuncTag
25 {
26 byte bDllNameLenth;//DLL名长度
27 char *szDllName;
28 WORD wFuncNum;//当前DLL的函数数量
29 byte bTab;//导入方式:0为序号导入 1为名称
30 vector<FuncTag>vFuncNAMEorNo;//注意:此时的序号已经去掉最高位
31 };
32 vector<DLLFuncTag>g_tagDllFunc;//存放IAT信息的结构体,成员为DLL名长度,DLL名,函数数量,标志(最高位为1则是序号,否则为一个字符串的地址),函数名列表
33
34
35 //先通过遍历获得下面结构体中各个成员的值 注:成员的位置皆为RVA
36 /*
37 1.将dwRelocAddr这4字节的地址放入重定位表中,使其在运行后该位置的值变为程序基址
38 2.先去dwCallAddr的位置,将那行代码修改为jmp dwJmpAddr(如果是mov eax,则直接修改即可,其他的则要填充多一个nop(0x90),以便对齐指令长度)
39 3.执行shellcode时,会将2的调用地址+5/+6作为返回地址压栈 (jmp指令除外)
40 4.将NewLatAddr的值,加上基址后,在得到的地址上取值,该地址上的值与原IAT所指向的值相同
41 5.执行完后,根据3得到的值,返回到调用指令的下一条指令上
42 */
43 struct IatAddrTab
44 {
45 DWORD dwCallAddr;//以便区分当前是什么类型下使用了这个IAT地址 注意,这里为整个调用代码的位置,而非调用的代码的函数地址的位置
46 BYTE bType;//该调用类型 0-7为mov eax、edx、esp、esi、ecx、ebx、ebp、edi 8为call 9为jmp (其中8和9可以归类成一个处理方式) 10为push
47 DWORD dwRelocAddr;//用于添加到重定位块中,该位置存放的为基址
48 WORD wIndex;//当前IAT位于加载表的下标 每个地址占4字节
49 DWORD dwOldIatAddr;//原IAT地址
50 DWORD dwNewIatAddr;//将要替换成的新IAT地址
51 DWORD dwJmpAddr;//shellcode所在的起始位置RVA
52 };
53 vector<IatAddrTab>g_tagIAT;//存放IAT替换地址的结构体,成员为IAT地址,以及一个调用地址位置,还有一个该IAT类型
54
55
56 vector<DWORD>g_IATaddrList;
57
58 struct tagRelocation
59 {
60 DWORD wR_Head;
61 vector<WORD>wR_Offset;
62 };
63 vector<tagRelocation>vOldReloction;
64
65
66 VOID GetKernel32Base(X86Assembler &a)
67 {
68 Label GetInfoBegin = a.newLabel();
69 Label cmpDllName = a.newLabel();
70 Label cmpChar = a.newLabel();
71 Label GetNextModule = a.newLabel();
72 Label GetBaseOver = a.newLabel();
73
74 a.push(ebx);
75 a.push(ecx);
76 a.push(edx);
77 a.push(esi);
78 a.push(edi);
79 a.mov(edx, esp);
80 a.sub(esp, 0x18);
81
82 a.mov(dword_ptr(esp, 0x00), 0x0065006B);
83 a.mov(dword_ptr(esp, 0x04), 0x006E0072);
84 a.mov(dword_ptr(esp, 0x08), 0x006C0065);
85 a.mov(dword_ptr(esp, 0x0C), 0x00320033);
86 a.mov(dword_ptr(esp, 0x10), 0x0064002E);
87 a.mov(dword_ptr(esp, 0x14), 0x006C006C);
88 a.xor_(eax, eax);
89 a.mov(esi, dword_ptr_abs(0x30).setSegment(fs));//获得PEB 同理mov esi,fs:[30]
90 a.mov(esi, dword_ptr(esi, 0x0C)); //取到dll的列表指针
91 a.mov(esi, dword_ptr(esi, 0x1C)); //取到初始化序模块化
92
93 a.bind(GetInfoBegin);//遍历模块信息
94 a.mov(edi, dword_ptr(esi, 8));//取到当前模块基址
95 a.lea(ebx, dword_ptr(esi, 0x1c));//取到UNICODE STRING结构
96 a.movzx(ecx, word_ptr(ebx));//取出长度
97 a.cmp (ecx, 24);//对比长度
98 a.jne(GetNextModule);//不等则获取下一个模块
99 a.mov(ebx, dword_ptr(ebx , 4));//取到字符串地址 此时ebx不再为结构地址
100 a.mov(ecx, 0);//用于遍历
101
102 a.bind(cmpDllName);//对比模块名字
103 a.cmp(ecx, 24);
104 //遍历到字符末尾 找到目标模块(先对的长度再对的字符,排除了前面同名后面A/W的情况)
105 a.jnl(GetBaseOver);//获取基址结束
106 a.xor_ (eax, eax);//清空容器
107 a.movzx(eax, word_ptr(ebx, ecx));
108 a.cmp(eax, 0x41);//如果是大写字符(41~5A)范围内,转成小写
109 a.jna(cmpChar);
110 a.cmp(eax, 0x5A);
111 a.ja(cmpChar);
112 a.add(eax, 0x20);//大写字符的值+0x20即转成小写字符
113
114 a.bind(cmpChar);//对比每个字符
115 a.cmp(ax, word_ptr(esp, ecx));//对比字符串内容
116 a.jne(GetNextModule);//不等则获取下一个模块
117 a.add(ecx, 2);
118 a.jmp(cmpDllName);
119
120 a.bind(GetNextModule);//获得下一个模块信息
121 a.mov(esi, dword_ptr(esi));//取得下一个初始化模块
122 a.test(esi, esi);
123 a.jnz(GetInfoBegin);//不为空则继续遍历
124
125 a.bind(GetBaseOver);
126 a.mov(eax, edi);
127 a.add(esp, 0x18);
128 a.pop(edi);
129 a.pop(esi);
130 a.pop(edx);
131 a.pop(ecx);
132 a.pop(ebx);
133 }
134
135 VOID GetLoadLibraryAAddr(X86Assembler &a)
136 {
137 //跳转标记
138 Label FindFuncAddr = a.newLabel();
139 Label FindFuncAddrOver = a.newLabel();
140
141 a.push(ebx);
142 a.push(ecx);
143 a.push(esi);
144 a.push(ebp);
145 //记得开始获取出来的都是RVA 要加上DLL的基址edi来取值
146 a.mov(eax, dword_ptr(edi, 0x3c));
147 a.mov(ebx, dword_ptr(edi, eax, 0, 0x78));//NT头+0x78 = 导入表RVA
148 //上面等价于[edi + eax + 0x78],如果没有0的话,他会把第三个参数当成2的N次方变成了edi + eax * 2的0x78次方
149 a.add(ebx, edi);//ebx=导入表
150 a.mov(ecx, dword_ptr(ebx, 0x18));//ecx=按名称导出个数
151 a.mov(esi, dword_ptr(ebx, 0x20));//esi=导出函数名称表rva
152 a.add(esi, edi);
153
154 a.bind(FindFuncAddr);
155 a.sub(ecx, 1);//从后面往前遍历 能少占用一个寄存器,但要记得先-1再遍历
156 a.jz(FindFuncAddrOver);//减到0即遍历完
157 a.mov(ebp, dword_ptr(esi, ecx, 2));//取到函数名称比拗最后一个函数名的RVA 等价于[esi,ecx*(2的n次方)]
158 a.add(ebp, edi);
159 a.cmp(dword_ptr(ebp), 0x64616F4C);
160 a.jne(FindFuncAddr);
161 a.cmp(dword_ptr(ebp, 4), 0x7262694C);
162 a.jne(FindFuncAddr);
163 a.cmp(dword_ptr(ebp, 8), 0x41797261);
164 a.jne(FindFuncAddr);
165 a.cmp(byte_ptr(ebp, 12), 0);//结束符 防止类似LoadLibrary和LoadLibraryA扩展函数名偏差出现
166 a.jne(FindFuncAddr);
167 //此时ecx为遍历的下标
168 a.mov(esi, dword_ptr(ebx, 0x24));//esi=导出函数序号表RVA(上面名称对比完 回收esi)
169 a.add(esi, edi);
170 a.movzx(ebp, word_ptr(esi, ecx, 1));//ebp=函数序号 ebp=[esi+ecx*2一次方]
171 //EBP:Get=2b0 Load=3c2
172 a.mov(esi, dword_ptr(ebx, 0x1c));//esi=函数地址表RVA
173 a.add(esi, edi);
174 a.mov(eax, dword_ptr(esi, ebp, 2));//地址=地址表+序号*2的2次方
175 a.add(eax, edi);
176 //此时eax为loadlibraryA地址
177 a.bind(FindFuncAddrOver);
178 a.pop(ebp);
179 a.pop(esi);
180 a.pop(ecx);
181 a.pop(ebx);
182 }
183
184 VOID GetGetProcAddressAddr(X86Assembler &a)
185 {
186 //跳转标记
187 Label FindFuncAddr = a.newLabel();
188 Label FindFuncAddrOver = a.newLabel();
189
190 a.push(ebx);
191 a.push(ecx);
192 a.push(esi);
193 a.push(ebp);
194 //记得开始获取出来的都是RVA 要加上DLL的基址edi来取值
195 a.mov(eax, dword_ptr(edi, 0x3c));
196 a.mov(ebx, dword_ptr(edi, eax, 0, 0x78));//NT头+0x78 = 导入表RVA
197 //上面等价于[edi + eax + 0x78],如果没有0的话,他会把第三个参数当成2的N次方变成了edi + eax * 2的0x78次方
198 a.add(ebx, edi);//ebx=导入表
199 a.mov(ecx, dword_ptr(ebx, 0x18));//ecx=按名称导出个数
200 a.mov(esi, dword_ptr(ebx, 0x20));//esi=导出函数名称表rva
201 a.add(esi, edi);
202
203 a.bind(FindFuncAddr);
204 a.sub(ecx, 1);//从后面往前遍历 能少占用一个寄存器,但要记得先-1再遍历
205 a.jz(FindFuncAddrOver);//减到0即遍历完
206 a.mov(ebp, dword_ptr(esi, ecx, 2));//取到函数名称比拗最后一个函数名的RVA 等价于[esi,ecx*(2的n次方)]
207 a.add(ebp, edi);
208 a.cmp(dword_ptr(ebp), 0x50746547);
209 a.jne(FindFuncAddr);
210 a.cmp(dword_ptr(ebp, 4), 0x41636f72);
211 a.jne(FindFuncAddr);
212 a.cmp(dword_ptr(ebp, 8), 0x65726464);
213 a.jne(FindFuncAddr);
214 a.cmp(word_ptr(ebp, 12), 0x7373);
215 a.jne(FindFuncAddr);
216 a.cmp(byte_ptr(ebp, 14), 0);//结束符 防止类似LoadLibrary和LoadLibraryA扩展函数名偏差出现
217 a.jne(FindFuncAddr);
218
219 //此时ecx为遍历的下标
220 a.mov(esi, dword_ptr(ebx, 0x24));//esi=导出函数序号表RVA(上面名称对比完 回收esi)
221 a.add(esi, edi);
222 a.movzx(ebp, word_ptr(esi, ecx, 1));//ebp=函数序号 ebp=[esi+ecx*2一次方]
223 //EBP:Get=2b0 Load=3c2
224 a.mov(esi, dword_ptr(ebx, 0x1c));//esi=函数地址表RVA
225 a.add(esi, edi);
226 a.mov(eax, dword_ptr(esi, ebp, 2));//地址=地址表+序号*2的2次方
227 a.add(eax, edi);
228 //此时eax为loadlibraryA地址
229 a.bind(FindFuncAddrOver);
230 a.pop(ebp);
231 a.pop(esi);
232 a.pop(ecx);
233 a.pop(ebx);
234 }
235 DWORD RVAtoFA(DWORD dwRVA) //RVA转文件地址
236 {
237 PIMAGE_DOS_HEADER pDosHead = PIMAGE_DOS_HEADER(g_pFileSrc);
238 PIMAGE_NT_HEADERS pNtHead = PIMAGE_NT_HEADERS((DWORD)pDosHead + pDosHead->e_lfanew);
239 PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)(pNtHead->FileHeader.SizeOfOptionalHeader + (DWORD)&pNtHead->OptionalHeader);
240 int iSectionNum = pNtHead->FileHeader.NumberOfSections;
241
242 for (int i = 0; i < iSectionNum; i++)
243 {
244 if (dwRVA >= pSection->VirtualAddress && dwRVA < (pSection->VirtualAddress + pSection->Misc.VirtualSize))
245 {
246 return (DWORD)g_pFileSrc + dwRVA - pSection->VirtualAddress + pSection->PointerToRawData;
247 }
248 pSection++;
249 }
250 return 0; //转换失败
251 }
252
253 DWORD FAtoRVA(DWORD dwFA) //文件地址转RVA
254 {
255 PIMAGE_DOS_HEADER pDosHead = PIMAGE_DOS_HEADER(g_pFileSrc);
256 PIMAGE_NT_HEADERS pNtHead = PIMAGE_NT_HEADERS((DWORD)pDosHead + pDosHead->e_lfanew);
257 PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)(pNtHead->FileHeader.SizeOfOptionalHeader + (DWORD)&pNtHead->OptionalHeader);
258 int iSectionNum = pNtHead->FileHeader.NumberOfSections;
259
260 for (int i = 0; i < iSectionNum; i++)
261 {
262 if (dwFA >= pSection->PointerToRawData && dwFA < (pSection->PointerToRawData + pSection->SizeOfRawData))
263 {
264 return (DWORD)dwFA - pSection->PointerToRawData + pSection->VirtualAddress;
265 }
266 pSection++;
267 }
268 return 0; //转换失败
269 }
270
271
272 BOOL LoadFile(char *pFileName) //获取文件内容
273 {
274 HANDLE hFile = CreateFileA(pFileName,
275 GENERIC_READ,
276 FILE_SHARE_READ,
277 NULL,
278 OPEN_EXISTING,
279 FILE_ATTRIBUTE_NORMAL,
280 0);
281 if (!hFile)
282 {
283 return false;
284 }
285 g_iFileSize = GetFileSize(hFile, NULL);
286
287 g_pFileSrc = (UCHAR*)malloc(g_iFileSize);
288 if (!g_pFileSrc)
289 {
290 cout << "申请内存失败" << endl;
291 return false;
292 }
293
294 if (!ReadFile(hFile, g_pFileSrc, g_iFileSize, NULL, NULL))
295 {
296 cout << "读取文件失败" << endl;
297 return false;
298 }
299
300 return true;
301 }
302
303
304 BOOL CheckPE() //检查PE文件格式
305 {
306 PIMAGE_DOS_HEADER pDosHead = PIMAGE_DOS_HEADER(g_pFileSrc);
307 PIMAGE_NT_HEADERS pNtHead = PIMAGE_NT_HEADERS((DWORD)pDosHead + pDosHead->e_lfanew);
308 if (pDosHead->e_magic != 0x5a4d || pNtHead->Signature != 0x4550)
309 {
310 return false;
311 }
312 g_iImageBase = pNtHead->OptionalHeader.ImageBase;
313 g_iFileAlignment = pNtHead->OptionalHeader.FileAlignment;
314 g_iSectionAlignment = pNtHead->OptionalHeader.SectionAlignment;
315 g_iOldOEP = pNtHead->OptionalHeader.AddressOfEntryPoint;
316 return true;
317 }
318
319
320
321 BOOL FindCodeAddr() //找到调用了IAT中的地址的代码位置
322 {
323 PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc;
324 PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew);
325 if (!pNtHead->OptionalHeader.DataDirectory[1].VirtualAddress)
326 {
327 return false;
328 }
329
330 PIMAGE_IMPORT_DESCRIPTOR pImpotrList = (PIMAGE_IMPORT_DESCRIPTOR)RVAtoFA(pNtHead->OptionalHeader.DataDirectory[1].VirtualAddress); //IAT
331 while (pImpotrList->FirstThunk)//获得该程序的IAT地址
332 {
333 int i = 0;
334 while (1)
335 {
336 DWORD iIatAddr = *(DWORD*)RVAtoFA(pImpotrList->FirstThunk + i * sizeof(DWORD));
337 if (!iIatAddr)
338 {
339 break;
340 }
341 DWORD dwIatAddr = pImpotrList->FirstThunk + i * sizeof(DWORD);
342 g_IATaddrList.push_back(dwIatAddr);
343 i++;
344 }
345 pImpotrList++;
346 }
347
348
349 //获取调用这些IAT地址的代码地址
350 for (int i = 0; i < g_iFileSize - 5; i++)
351 {
352 //mov eax
353 if (g_pFileSrc[i] == 0xA1)
354 {
355 DWORD IatAddr = *(DWORD*)(g_pFileSrc + i + 1);
356 for (int iNum = 0; iNum < g_IATaddrList.size(); iNum++)
357 {
358 if (g_IATaddrList[iNum] == (IatAddr^g_iImageBase))
359 {
360 IatAddrTab IatInfo;
361 IatInfo.dwCallAddr = FAtoRVA(i);
362 IatInfo.bType = 0;
363 IatInfo.wIndex = iNum;
364 IatInfo.dwOldIatAddr = g_IATaddrList[iNum];
365 g_tagIAT.push_back(IatInfo);
366 i += 4; //for循环会加1,操作符+地址共5字节
367 continue;
368 }
369 }
370 }
371
372 //mov edx、esp、esi、ecx、ebx、ebp、edi
373 if (g_pFileSrc[i] == 0x8B && (g_pFileSrc[i + 1] == 0x15 || g_pFileSrc[i + 1] == 0x25 || g_pFileSrc[i + 1] == 0x35 ||
374 g_pFileSrc[i + 1] == 0x0D || g_pFileSrc[i + 1] == 0x1D || g_pFileSrc[i + 1] == 0x2D || g_pFileSrc[i + 1] == 0x3D))
375 {
376 DWORD IatAddr = *(DWORD*)(g_pFileSrc + i + 2);
377 for (int iNum = 0; iNum < g_IATaddrList.size(); iNum++)
378 {
379 if (g_IATaddrList[iNum] == (IatAddr^g_iImageBase))
380 {
381 DWORD ddddd = FAtoRVA(i);
382 if (g_pFileSrc[i + 1] == 0x15) //edx
383 {
384 IatAddrTab IatInfo;
385 IatInfo.dwCallAddr = FAtoRVA(i);
386 IatInfo.bType = 1;
387 IatInfo.wIndex = iNum;
388 IatInfo.dwOldIatAddr = g_IATaddrList[iNum];
389 g_tagIAT.push_back(IatInfo);
390 }
391 else if (g_pFileSrc[i + 1] == 0x25) //esp
392 {
393 IatAddrTab IatInfo;
394 IatInfo.dwCallAddr = FAtoRVA(i);
395 IatInfo.bType = 2;
396 IatInfo.wIndex = iNum;
397 IatInfo.dwOldIatAddr = g_IATaddrList[iNum];
398 g_tagIAT.push_back(IatInfo);
399 }
400 else if (g_pFileSrc[i + 1] == 0x35) //esi
401 {
402 IatAddrTab IatInfo;
403 IatInfo.dwCallAddr = FAtoRVA(i);
404 IatInfo.bType = 3;
405 IatInfo.wIndex = iNum;
406 IatInfo.dwOldIatAddr = g_IATaddrList[iNum];
407 g_tagIAT.push_back(IatInfo);
408 }
409 else if (g_pFileSrc[i + 1] == 0x0D) //ecx
410 {
411 IatAddrTab IatInfo;
412 IatInfo.dwCallAddr = FAtoRVA(i);
413 IatInfo.bType = 4;
414 IatInfo.wIndex = iNum;
415 IatInfo.dwOldIatAddr = g_IATaddrList[iNum];
416 g_tagIAT.push_back(IatInfo);
417 }
418 else if (g_pFileSrc[i + 1] == 0x1D) //ebx
419 {
420 IatAddrTab IatInfo;
421 IatInfo.dwCallAddr = FAtoRVA(i);
422 IatInfo.bType = 5;
423 IatInfo.wIndex = iNum;
424 IatInfo.dwOldIatAddr = g_IATaddrList[iNum];
425 g_tagIAT.push_back(IatInfo);
426 }
427 else if (g_pFileSrc[i + 1] == 0x2D) //ebp
428 {
429 IatAddrTab IatInfo;
430 IatInfo.dwCallAddr = FAtoRVA(i);
431 IatInfo.bType = 6;
432 IatInfo.wIndex = iNum;
433 IatInfo.dwOldIatAddr = g_IATaddrList[iNum];
434 g_tagIAT.push_back(IatInfo);
435 }
436 else if (g_pFileSrc[i + 1] == 0x3D) //edi
437 {
438 IatAddrTab IatInfo;
439 IatInfo.dwCallAddr = FAtoRVA(i);
440 IatInfo.bType = 7;
441 IatInfo.wIndex = iNum;
442 IatInfo.dwOldIatAddr = g_IATaddrList[iNum];
443 g_tagIAT.push_back(IatInfo);
444 }
445 i += 5; //for循环会加1,操作符+地址共6字节
446 continue;
447 }
448 }
449 }
450
451 //call jmp push
452 if (g_pFileSrc[i] == 0xFF && (g_pFileSrc[i + 1] == 0x15 || g_pFileSrc[i + 1] == 0x25 || g_pFileSrc[i + 1] == 0x35))
453 {
454 DWORD IatAddr = *(DWORD*)(g_pFileSrc + i + 2);
455 for (int iNum = 0; iNum < g_IATaddrList.size(); iNum++)
456 {
457 if (g_IATaddrList[iNum] == (IatAddr^g_iImageBase))
458 {
459 DWORD ddddd = FAtoRVA(i);
460 if (g_pFileSrc[i + 1] == 0x15) //call
461 {
462 IatAddrTab IatInfo;
463 IatInfo.dwCallAddr = FAtoRVA(i);
464 IatInfo.bType = 8;
465 IatInfo.wIndex = iNum;
466 IatInfo.dwOldIatAddr = g_IATaddrList[iNum];
467 g_tagIAT.push_back(IatInfo);
468 }
469 else if (g_pFileSrc[i + 1] == 0x25) //jmp
470 {
471 IatAddrTab IatInfo;
472 IatInfo.dwCallAddr = FAtoRVA(i);
473 IatInfo.bType = 9;
474 IatInfo.wIndex = iNum;
475 IatInfo.dwOldIatAddr = g_IATaddrList[iNum];
476 g_tagIAT.push_back(IatInfo);
477 }
478 else if (g_pFileSrc[i + 1] == 0x35) //push
479 {
480 IatAddrTab IatInfo;
481 IatInfo.dwCallAddr = FAtoRVA(i);
482 IatInfo.bType = 10;
483 IatInfo.wIndex = iNum;
484 IatInfo.dwOldIatAddr = g_IATaddrList[iNum];
485 g_tagIAT.push_back(IatInfo);
486 }
487 i += 5; //for循环会加1,操作符+地址共6字节
488 continue;
489 }
490 }
491 }
492 }
493
494 return true;
495 }
496
497
498 bool SaveDll() //保存DLL相关数据
499 {
500 PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc;
501 PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew);
502 DWORD dwImportRVA = pNtHead->OptionalHeader.DataDirectory[1].VirtualAddress;
503 PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)RVAtoFA(dwImportRVA);
504 while (pImport->FirstThunk)
505 {
506 DLLFuncTag tagDllList;//Dll信息结构
507
508 char *szDllName = (char*)RVAtoFA(pImport->Name);
509 int iDllNameLen = strlen(szDllName) + 1;
510 char *szNewDllName = (char*)malloc(iDllNameLen);
511 memcpy(szNewDllName, szDllName, iDllNameLen);
512
513 tagDllList.szDllName = szNewDllName;
514 tagDllList.bDllNameLenth = iDllNameLen;
515
516 PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)RVAtoFA(pImport->FirstThunk);
517 while (pIAT->u1.Function)
518 {
519 FuncTag tagFuncInfo;//函数信息结构
520 DWORD dwFuncAddr = pIAT->u1.Function;
521 if (dwFuncAddr & 0x80000000)
522 {
523 tagDllList.bTab = 0;//按序号导入
524 tagFuncInfo.iFuncNameLenth = 4;
525 tagFuncInfo.szFuncName = (char*)(dwFuncAddr ^ 0x80000000);
526 tagDllList.vFuncNAMEorNo.push_back(tagFuncInfo);
527 }
528 else
529 {
530 tagDllList.bTab = 1;//按名称导入
531 PIMAGE_IMPORT_BY_NAME pFunc = (PIMAGE_IMPORT_BY_NAME)RVAtoFA(pIAT->u1.Function);
532 int iFuncNameLen = strlen(pFunc->Name) + 1;
533 char *szFuncName = (char*)malloc(iFuncNameLen);
534 memcpy(szFuncName, pFunc->Name, iFuncNameLen);
535 tagFuncInfo.iFuncNameLenth = iFuncNameLen;
536 tagFuncInfo.szFuncName = szFuncName;
537 tagDllList.vFuncNAMEorNo.push_back(tagFuncInfo);
538 }
539 pIAT++;
540 }
541 tagDllList.wFuncNum = tagDllList.vFuncNAMEorNo.size();
542 g_tagDllFunc.push_back(tagDllList);
543 pImport++;
544 }
545
546 //将IAT表信息隐藏(每个DLL只有一个导入函数)
547 PIMAGE_IMPORT_DESCRIPTOR pImpotrList = (PIMAGE_IMPORT_DESCRIPTOR)RVAtoFA(pNtHead->OptionalHeader.DataDirectory[1].VirtualAddress);
548 while (pImpotrList->FirstThunk)
549 {
550 PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)RVAtoFA(pImpotrList->FirstThunk);
551 PIMAGE_THUNK_DATA pINT = (PIMAGE_THUNK_DATA)RVAtoFA(pImpotrList->OriginalFirstThunk);
552 pIAT++;//保留第一个
553 pINT++;
554 while (pIAT->u1.Function)//将IAT清空
555 {
556 pIAT->u1.Function = 0;
557 pIAT++;
558 }
559 while (pINT->u1.Function)//将INT清空
560 {
561 pINT->u1.Function = 0;
562 pINT++;
563 }
564 pImpotrList++;
565 }
566 return true;
567 }
568
569
570
571
572 bool NewIat()
573 {
574 PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc;
575 PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew);
576 PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader);
577 for (int i = 0; i < pNtHead->FileHeader.NumberOfSections; i++)
578 {
579 //将每个节都改为可写属性,以便在后续修改。
580 //本来只修改.text节的属性即可,但由于该节的位置不在data数组里面记录,单凭节名判断未必准确,所以将所以节都改为可写-
581 pSection->Characteristics += 0x80000000;
582 }
583 if (!(pNtHead->OptionalHeader.DataDirectory[5].VirtualAddress))//当当前程序没有重定位表
584 {
585 PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader);
586 pSection += pNtHead->FileHeader.NumberOfSections - 1;
587 int iNewSectionFileAddr = pSection->PointerToRawData + pSection->SizeOfRawData;
588 int iNewSectionFileMapAddr = 0;
589 if (!(pSection->Misc.VirtualSize % g_iSectionAlignment))
590 {
591 iNewSectionFileMapAddr = pSection->VirtualAddress + pSection->Misc.VirtualSize;
592 }
593 else
594 {
595 iNewSectionFileMapAddr = pSection->VirtualAddress + pSection->Misc.VirtualSize
596 + g_iSectionAlignment - (pSection->Misc.VirtualSize % g_iSectionAlignment);
597 }
598
599 pSection++;
600 memcpy(pSection->Name, ".KD", 3);
601 pSection->VirtualAddress = iNewSectionFileMapAddr;
602 pSection->PointerToRawData = iNewSectionFileAddr;
603 pSection->Characteristics = (0x20000000 | 0x40000000 | 0x80000000 | 0x40); //节属性 可读可写可执行已被初始化
604 pNtHead->FileHeader.NumberOfSections += 1;//节表数量+1
605
606
607 //将IAT的数据压入新节中数据排列分别为DLL数量(2字节)、DLL名字长度、该
608 int iAddIatLenth = 0;//已经增加的iat数据长度
609 //先添加2字节数据说明该程序的DLL数量
610 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 1);
611 byte bDllNum = g_tagDllFunc.size();
612 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, &bDllNum, 1);
613 iAddIatLenth += 2;
614 for (int i = 0; i < bDllNum; i++)
615 {
616 //添加DLL名长度
617 int bDllNameLenth = g_tagDllFunc[i].bDllNameLenth;
618 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 2);
619 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, &bDllNameLenth, 2);
620 iAddIatLenth += 2;
621
622 //添加DLL名
623 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + bDllNameLenth);
624 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, g_tagDllFunc[i].szDllName, bDllNameLenth);
625 iAddIatLenth += bDllNameLenth;
626
627 //添加该DLL中的导入函数数量 方便后续遍历
628 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 4);
629 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (DWORD*)&g_tagDllFunc[i].wFuncNum, 4);
630 iAddIatLenth += 4;
631
632 //添加该DLL的导入方式 0为序号1为名称
633 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 1);
634 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (byte*)&g_tagDllFunc[i].bTab, 1);
635 iAddIatLenth += 1;
636 for (int j = 0; j < g_tagDllFunc[i].wFuncNum; j++)
637 {
638 //添加函数名或序号
639 if (!(g_tagDllFunc[i].bTab)) //序号
640 {
641 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 6);//2长度4序号
642 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (WORD*)&g_tagDllFunc[i].vFuncNAMEorNo[j].iFuncNameLenth, 2);
643 iAddIatLenth += 2;
644 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (DWORD*)&g_tagDllFunc[i].vFuncNAMEorNo[j].szFuncName, 4);
645 iAddIatLenth += 4;
646 }
647 else //名字
648 {
649 int iFuncNameLenth = g_tagDllFunc[i].vFuncNAMEorNo[j].iFuncNameLenth;//长度
650 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 2 + iFuncNameLenth);//前2字节存放长度 后面为函数名称
651 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (WORD*)&iFuncNameLenth, 2);
652 iAddIatLenth += 2;
653 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, g_tagDllFunc[i].vFuncNAMEorNo[j].szFuncName, iFuncNameLenth);
654 iAddIatLenth += iFuncNameLenth;
655 }
656 }
657 }
658
659 //获取新的OEP并修改旧的OEP
660 g_iNewOEP = iNewSectionFileMapAddr + iAddIatLenth;//新节的
661 pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc;
662 pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew);
663 pNtHead->OptionalHeader.AddressOfEntryPoint = g_iNewOEP;
664
665 JitRuntime _x86RunTimeObject;
666 X86Assembler a(&_x86RunTimeObject);
667
668 //当程序没有重定位表时,根据call 0000 0000来获得进程基址,有重定位表时则根据重定位表
669 char szGetOEP[] = { 0xE8, 0x00, 0x00, 0x00, 0x00 }; //同理jit.call(0x00000000);
670 a.pop(eax);
671 a.sub(eax, 5);//此时得到oep所在的地址 oep距离基址隔着
672 a.sub(eax, g_iNewOEP);//OEP所在的基址-偏移 得到基址
673 a.mov(ebp, eax); //保存进程基址到ebp
674 a.add(eax, g_iOldOEP);
675 a.jmp(eax);
676
677 PVOID szJit = a.make();
678 int iJitLenth = a.getCodeSize() + 5; //包括e8 0000 0000;
679
680 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + iJitLenth);
681 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, szGetOEP, 5);
682 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth + 5, szJit, iJitLenth);
683
684 int iAddSrcLen = iAddIatLenth + iJitLenth;//一共增加的代码
685 //完善节长度等数据 保守起见重新获取节表信息
686 pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc;
687 pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew);
688 pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader);
689 pSection += pNtHead->FileHeader.NumberOfSections - 1;
690 if (!(iAddSrcLen%g_iFileAlignment))
691 {
692 pSection->SizeOfRawData = iAddSrcLen;
693 }
694 else
695 {
696 pSection->SizeOfRawData = iAddSrcLen + g_iFileAlignment - (iAddSrcLen%g_iFileAlignment);
697 }
698 if (!(iAddSrcLen%g_iSectionAlignment))
699 {
700 pSection->Misc.VirtualSize = iAddSrcLen;
701 }
702 else
703 {
704 pSection->Misc.VirtualSize = iAddSrcLen + g_iSectionAlignment - (iAddSrcLen%g_iSectionAlignment);
705 }
706 pNtHead->OptionalHeader.SizeOfImage += pSection->Misc.VirtualSize;
707
708 if (iAddSrcLen != pSection->SizeOfRawData)//当新增长度与对齐后的节长度不相等时,将其补全
709 {
710 int iLenth = pSection->SizeOfRawData;//先保存,以免扩容后原地址被回收
711 //g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iLenth);
712 UCHAR *uuu = (UCHAR*)malloc(g_iFileSize + iAddSrcLen);
713 memcpy(uuu, g_pFileSrc, g_iFileSize + iAddSrcLen);
714 g_pFileSrc = (UCHAR*)malloc(g_iFileSize + iLenth);
715 memcpy(g_pFileSrc, uuu, g_iFileSize + iAddSrcLen);
716 memset(g_pFileSrc + g_iFileSize + iAddSrcLen, 0, iLenth - iAddSrcLen);
717 }
718 g_iFileSize += pSection->SizeOfRawData;
719 }
720
721
722
723 /////////////////////////////////////////////////////////////////////////////
724 //当有重定位表时,先保存相关数据,删除重定位表,新增节,再在后面还原重定位表
725 else
726 {
727 //把重定位表数据移动到新节当中
728 //获取位置和长度
729 int iRelocationAddr = pNtHead->OptionalHeader.DataDirectory[5].VirtualAddress;
730 int iRelocationLenth = pNtHead->OptionalHeader.DataDirectory[5].Size;//数据长度
731 char *szR_Src = (char*)malloc(iRelocationLenth);
732 memcpy(szR_Src, (char*)RVAtoFA(iRelocationAddr), iRelocationLenth);
733
734 PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader);
735 char szR_Name[8] = { 0 };
736 int iR_MapLenth = 0;//节中映射长度
737 int iR_FileLenth = 0;//节中文件长度
738 while (1)
739 {
740 if (pSection->VirtualAddress == iRelocationAddr) //定位到重定位表节表
741 {
742 strcpy(szR_Name, (char*)pSection->Name);
743 iR_MapLenth = pSection->Misc.VirtualSize;
744 iR_FileLenth = pSection->SizeOfRawData;
745 break;
746 }
747 pSection++;
748 }
749
750 //删除重定位表相关信息
751 memset(g_pFileSrc + g_iFileSize - iR_FileLenth, 0, iR_FileLenth);//把重定位表数据用0覆盖
752 memset(pSection, 0, sizeof(IMAGE_SECTION_HEADER));
753 pNtHead->FileHeader.NumberOfSections--;
754 //调整文件内存大小
755 int iAlignmentSize = iR_MapLenth % g_iSectionAlignment;
756 if (!iAlignmentSize)
757 {
758 pNtHead->OptionalHeader.SizeOfImage -= iR_MapLenth; //调整文件内存大小
759 }
760 else
761 {
762 pNtHead->OptionalHeader.SizeOfImage =
763 pNtHead->OptionalHeader.SizeOfImage
764 - (iR_MapLenth - iAlignmentSize + g_iSectionAlignment);
765 }
766 g_iFileSize -= iR_FileLenth;
767
768
769 //新增节
770 pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader);
771 pSection += pNtHead->FileHeader.NumberOfSections - 1;
772 int iNewSectionFileAddr = pSection->PointerToRawData + pSection->SizeOfRawData;
773 int iNewSectionFileMapAddr = 0;
774 if (!(pSection->Misc.VirtualSize % g_iSectionAlignment))
775 {
776 iNewSectionFileMapAddr = pSection->VirtualAddress + pSection->Misc.VirtualSize;
777 }
778 else
779 {
780 iNewSectionFileMapAddr = pSection->VirtualAddress + pSection->Misc.VirtualSize
781 + g_iSectionAlignment - (pSection->Misc.VirtualSize % g_iSectionAlignment);
782 }
783
784 pSection++;
785 memcpy(pSection->Name, ".KD", 3);
786 pSection->VirtualAddress = iNewSectionFileMapAddr;
787 pSection->PointerToRawData = iNewSectionFileAddr;
788 pSection->Characteristics = (0x20000000 | 0x40000000 | 0x80000000 | 0x40); //节属性 可读可写可执行已被初始化
789 pNtHead->FileHeader.NumberOfSections += 1;//节表数量+1
790
791
792 //将IAT的数据压入新节中数据排列分别为DLL数量(2字节)、DLL名字长度、该
793 int iAddIatLenth = 0;//已经增加的iat数据长度
794 //先添加1字节数据说明该程序的DLL数量
795 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 1);
796 byte bDllNum = g_tagDllFunc.size();
797 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, &bDllNum, 1);
798 iAddIatLenth += 1;
799 for (int i = 0; i < bDllNum; i++)
800 {
801 //添加DLL名长度
802 byte bDllNameLenth = g_tagDllFunc[i].bDllNameLenth;
803 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 1);
804 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, &bDllNameLenth, 1);
805 iAddIatLenth += 1;
806
807 //添加DLL名
808 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + bDllNameLenth);
809 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, g_tagDllFunc[i].szDllName, bDllNameLenth);
810 iAddIatLenth += bDllNameLenth;
811
812 //添加该DLL中的导入函数数量 方便后续遍历
813 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 2);
814 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (DWORD*)&g_tagDllFunc[i].wFuncNum, 2);
815 iAddIatLenth += 2;
816
817 //添加该DLL的导入方式 0为序号1为名称
818 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 1);
819 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (byte*)&g_tagDllFunc[i].bTab, 1);
820 iAddIatLenth += 1;
821 for (int j = 0; j < g_tagDllFunc[i].wFuncNum; j++)
822 {
823 //添加函数名或序号
824 if (!(g_tagDllFunc[i].bTab)) //序号
825 {
826 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 5);//1长度4序号
827 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (BYTE*)&g_tagDllFunc[i].vFuncNAMEorNo[j].iFuncNameLenth, 1);
828 iAddIatLenth += 1;
829 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (DWORD*)&g_tagDllFunc[i].vFuncNAMEorNo[j].szFuncName, 4);
830 iAddIatLenth += 4;
831 }
832 else //名字
833 {
834 int iFuncNameLenth = g_tagDllFunc[i].vFuncNAMEorNo[j].iFuncNameLenth;//长度
835 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + 1 + iFuncNameLenth);//前2字节存放长度 后面为函数名称
836 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, (BYTE*)&iFuncNameLenth, 1);
837 iAddIatLenth += 1;
838 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth, g_tagDllFunc[i].vFuncNAMEorNo[j].szFuncName, iFuncNameLenth);
839 iAddIatLenth += iFuncNameLenth;
840 }
841 }
842 }
843
844 //存放加载的函数地址表的RVA
845 int iLoadAddressTabRVA = iNewSectionFileMapAddr + iAddIatLenth;
846 int iLoadIatLenth = g_IATaddrList.size() * 4;//用于存放加载的函数地址表长度 此处多4字节来存放基址
847
848
849 //获取新的OEP并修改旧的OEP
850 g_iNewOEP = iNewSectionFileMapAddr + iAddIatLenth + iLoadIatLenth;
851 pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc;
852 pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew);
853 pNtHead->OptionalHeader.AddressOfEntryPoint = g_iNewOEP;
854
855 JitRuntime _x86RunTimeObject;
856 X86Assembler a(&_x86RunTimeObject);
857
858 //跳转标记
859 Label LoadDllBegin = a.newLabel();
860 Label LoadDllOver = a.newLabel();
861
862 Label NameExport = a.newLabel();
863 Label NameExportBegin = a.newLabel();
864 Label NameExportOver = a.newLabel();
865 Label NoExportBegin = a.newLabel();
866 Label NoExportOver = a.newLabel();
867
868 //test
869 Label lTest = a.newLabel();
870
871 //当有重定位表时,将NewOEP+1新增到重定位项中,重定位后的地址-OldOEP即可得到新的基址
872 //这里push g_iOldOEP + g_iImageBase而不是g_iImageBase(直接得到新基址 不用再-旧OEP),是因为push完还要ret到旧OEP
873 //执行完这段后,栈上是旧OEP的地址,ebx是程序基址
874 a.push(g_iOldOEP + g_iImageBase);
875 a.mov(ebx, dword_ptr(esp));
876 a.sub(ebx, g_iOldOEP);
877
878 /*a.call(lTest);
879 a.bind(lTest);
880 a.pop(eax);*/
881
882 a.pusha();
883 a.push(ebx);//将程序基址保存到栈上
884 a.sub(esp, 0x8);
885 a.mov(ebp, esp); //ebp从上往下分别是LoadLibraryA函数地址、GetProcAddress函数地址和程序基址 ebp-4为Dll基址 -8为填充函数加载地址起始地址
886 a.sub(esp, 0x8);
887
888 GetKernel32Base(a);
889 a.mov(edi, eax);//edi为所遍历到的DLL基址
890
891 //计算函数地址
892 GetLoadLibraryAAddr(a);
893 a.mov(dword_ptr(ebp, 0), eax);//保存LoadLibraryA的值到栈上
894 GetGetProcAddressAddr(a);
895 a.mov(dword_ptr(ebp, 4), eax);//保存GetProcAddress的值到栈上
896 a.mov(eax, iLoadAddressTabRVA);
897 a.add(eax, dword_ptr(ebp, 8));//填充函数地址RVA+程序基址
898 a.mov(dword_ptr(ebp, -8), eax);//放到ebp-8的地址上
899
900
901 //开始遍历IAT数据,填充函数加载地址表
902 a.mov(esi, iNewSectionFileMapAddr);
903 a.add(esi, dword_ptr(ebp, 8));//esi为IAT数据起点
904 a.mov(ebx, 1);//以ebx开始遍历 达到长度 退出
905
906
907 //加载DLL
908 a.bind(LoadDllBegin);
909 a.cmp(ebx, iAddIatLenth);//如果遍历长度大于等于IAT数据长度
910 a.jnl(LoadDllOver);
911 a.movzx(ecx, byte_ptr(esi, ebx));//取得DLL名长度
912 a.add(ebx, 1);//+Dll名长度的变量1
913 a.lea(eax, dword_ptr(esi,ebx));//获得函数名地址
914 a.push(eax);
915 a.add(ebx, ecx);//+DLL名长度
916 a.mov(eax, dword_ptr(ebp));//获得loadlibrary地址
917 a.call(eax);
918 a.mov(dword_ptr(ebp,-4),eax);//ebp为load.. +4为get.. +8为程序基址 -4为当前Dll基址 -8为填充函数加载地址位置
919 a.movzx(edi, word_ptr(esi, ebx));//取出该DLL导出函数数量
920 a.add(ebx, 2);
921 a.movzx(edx, byte_ptr(esi, ebx));//取出导出方式
922 a.add(ebx, 1);
923 a.cmp(edx, 1);//为1时,名称导出
924 a.je(NameExportBegin);
925
926
927 //序号导出
928 a.bind(NoExportBegin);//序号导出循环起点
929 a.cmp(edi, 0);
930 a.je(NoExportOver);
931 a.add(ebx, 1);
932 a.mov(eax, dword_ptr(esi, ebx));//取得序号
933 a.add(ebx, 4);
934 a.push(eax);
935 a.push(dword_ptr(ebp, -4));
936 a.mov(eax, dword_ptr(ebp, 4));//获得GetProcAddress
937 a.call(eax);
938 a.mov(edx, dword_ptr(ebp, -8));//取得装载函数表
939 a.mov(dword_ptr(edx), eax);
940 a.add(dword_ptr(ebp, -8), 4);//装载函数表RVA+4
941 a.sub(edi, 1);
942 a.jmp(NoExportBegin);
943 a.bind(NoExportOver);//序号导出循环终点
944 a.jmp(LoadDllBegin); //重新加载新DLL
945
946 //名称导出
947 a.bind(NameExportBegin);//名称导出循环起点
948 a.cmp(edi, 0);
949 a.je(NameExportOver);
950 a.movzx(ecx, byte_ptr(esi, ebx));//取得名称长度
951 a.add(ebx, 1);
952 a.lea(eax, dword_ptr(esi, ebx));//名称地址
953 a.push(eax);
954 a.add(ebx, ecx);
955 a.push(dword_ptr(ebp, -4));
956 a.mov(eax, dword_ptr(ebp, 4));
957 a.call(eax);
958 a.mov(edx, dword_ptr(ebp, -8));//取得装载函数表
959 a.mov(dword_ptr(edx), eax);
960 a.add(dword_ptr(ebp, -8), 4);//装载函数表RVA+4
961 a.sub(edi, 1);
962 a.jmp(NameExportBegin);
963 a.bind(NameExportOver);//名称导出循环终点
964 a.jmp(LoadDllBegin); //重新加载新DLL
965
966
967
968 ///////////开始构造替换调用代码的shellcode//////////////
969 //注意esp为当前操作的栈顶 ebp+8为程序所在基址
970 int iNewJitBeginAddrRva = iNewSectionFileMapAddr + iAddIatLenth + iLoadIatLenth; //替换的shellcode开始的地址
971 int iNewJitLenth = a.getCodeSize();
972 for (int i = 0; i < g_tagIAT.size(); i++)
973 {
974 if (g_tagIAT[i].bType == 0) //EAX
975 {
976 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4;
977 a.push(ebx);
978 a.push(ebx);
979 a.push(ebx);
980 a.push(esi);
981 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 5);
982 a.mov(esi, g_iImageBase);//程序基址 后续会将这个位置添加到重定位块处,运行时即变为程序基址了
983 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode开始的位置+当前jit长度 再往回4字节 即为存放基址的位置
984 a.lea(ebx, dword_ptr(ebx, esi));
985 a.mov(dword_ptr(esp, 0xC), ebx);//当前指令所在RVA+5+程序基址 =返回地址
986 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr);
987 a.lea(ebx, dword_ptr(ebx, esi));
988 a.mov(ebx, dword_ptr(ebx));
989 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函数地址的地址
990 a.pop(esi);
991 a.pop(ebx);
992 a.pop(eax);
993 a.ret();
994 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth;
995 iNewJitLenth = a.getCodeSize();
996 }
997 else if (g_tagIAT[i].bType == 1) //EDX
998 {
999 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4;
1000 a.push(ebx);
1001 a.push(ebx);
1002 a.push(ebx);
1003 a.push(esi);
1004 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6);
1005 a.mov(esi, g_iImageBase);//程序基址 后续会将这个位置添加到重定位块处,运行时即变为程序基址了
1006 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode开始的位置+当前jit长度 再往回4字节 即为存放基址的位置
1007 a.lea(ebx, dword_ptr(ebx, esi));
1008 a.mov(dword_ptr(esp, 0xC), ebx);//当前指令所在RVA+5+程序基址 =返回地址
1009 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr);
1010 a.lea(ebx, dword_ptr(ebx, esi));
1011 a.mov(ebx, dword_ptr(ebx));
1012 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函数地址的地址
1013 a.pop(esi);
1014 a.pop(ebx);
1015 a.pop(edx);
1016 a.ret();
1017 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth;
1018 iNewJitLenth = a.getCodeSize();
1019 }
1020 else if (g_tagIAT[i].bType == 2) //ESP
1021 {
1022 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4;
1023 a.push(ebx);
1024 a.push(ebx);
1025 a.push(ebx);
1026 a.push(esi);
1027 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6);
1028 a.mov(esi, g_iImageBase);//程序基址 后续会将这个位置添加到重定位块处,运行时即变为程序基址了
1029 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode开始的位置+当前jit长度 再往回4字节 即为存放基址的位置
1030 a.lea(ebx, dword_ptr(ebx, esi));
1031 a.mov(dword_ptr(esp, 0xC), ebx);//当前指令所在RVA+6+程序基址 =返回地址
1032 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr);
1033 a.lea(ebx, dword_ptr(ebx, esi));
1034 a.mov(ebx, dword_ptr(ebx));
1035 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函数地址的地址
1036 a.pop(esi);
1037 a.pop(ebx);
1038 a.pop(esp);
1039 a.ret();
1040 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth;
1041 iNewJitLenth = a.getCodeSize();
1042 }
1043 else if (g_tagIAT[i].bType == 3) //ESI
1044 {
1045 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4;
1046 a.push(ebx);
1047 a.push(ebx);
1048 a.push(ebx);
1049 a.push(esi);
1050 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr);
1051 a.mov(esi, g_iImageBase);//程序基址 后续会将这个位置添加到重定位块处,运行时即变为程序基址了
1052 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode开始的位置+当前jit长度 再往回4字节 即为存放基址的位置
1053 a.lea(ebx, dword_ptr(ebx, esi));
1054 a.mov(ebx, dword_ptr(ebx));
1055 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函数地址的地址
1056 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6);
1057 a.lea(ebx, dword_ptr(ebx, esi));
1058 a.mov(dword_ptr(esp, 0xC), ebx);//当前指令所在RVA+6+程序基址 =返回地址
1059 a.pop(esi);
1060 a.pop(ebx);
1061 a.pop(esi);
1062 a.ret();
1063 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth;
1064 iNewJitLenth = a.getCodeSize();
1065 }
1066 else if (g_tagIAT[i].bType == 4) //ECX
1067 {
1068 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4;
1069 a.push(ebx);
1070 a.push(ebx);
1071 a.push(ebx);
1072 a.push(esi);
1073 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6);
1074 a.mov(esi, g_iImageBase);//程序基址 后续会将这个位置添加到重定位块处,运行时即变为程序基址了
1075 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode开始的位置+当前jit长度 再往回4字节 即为存放基址的位置
1076 a.lea(ebx, dword_ptr(ebx, esi));
1077 a.mov(dword_ptr(esp, 0xC), ebx);//当前指令所在RVA+6+程序基址 =返回地址
1078 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr);
1079 a.lea(ebx, dword_ptr(ebx, esi));
1080 a.mov(ebx, dword_ptr(ebx));
1081 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函数地址的地址
1082 a.pop(esi);
1083 a.pop(ebx);
1084 a.pop(ecx);
1085 a.ret();
1086 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth;
1087 iNewJitLenth = a.getCodeSize();
1088 }
1089 else if (g_tagIAT[i].bType == 5) //EBX
1090 {
1091 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4;
1092 a.push(ebx);
1093 a.push(ebx);
1094 a.push(ebx);
1095 a.push(esi);
1096 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6);
1097 a.mov(esi, g_iImageBase);//程序基址 后续会将这个位置添加到重定位块处,运行时即变为程序基址了
1098 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode开始的位置+当前jit长度 再往回4字节 即为存放基址的位置
1099 a.lea(ebx, dword_ptr(ebx, esi));
1100 a.mov(dword_ptr(esp, 0xC), ebx);//当前指令所在RVA+6+程序基址 =返回地址
1101 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr);
1102 a.lea(ebx, dword_ptr(ebx, esi));
1103 a.mov(ebx, dword_ptr(ebx));
1104 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函数地址的地址
1105 a.pop(esi);
1106 a.pop(ebx);
1107 a.pop(ebx);
1108 a.ret();
1109 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth;
1110 iNewJitLenth = a.getCodeSize();
1111 }
1112 else if (g_tagIAT[i].bType == 6) //EBP
1113 {
1114 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4;
1115 a.push(ebx);
1116 a.push(ebx);
1117 a.push(ebx);
1118 a.push(esi);
1119 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6);
1120 a.mov(esi, g_iImageBase);//程序基址 后续会将这个位置添加到重定位块处,运行时即变为程序基址了
1121 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode开始的位置+当前jit长度 再往回4字节 即为存放基址的位置
1122 a.lea(ebx, dword_ptr(ebx, esi));
1123 a.mov(dword_ptr(esp, 0xC), ebx);//当前指令所在RVA+6+程序基址 =返回地址
1124 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr);
1125 a.lea(ebx, dword_ptr(ebx, esi));
1126 a.mov(ebx, dword_ptr(ebx));
1127 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函数地址的地址
1128 a.pop(esi);
1129 a.pop(ebx);
1130 a.pop(ebp);
1131 a.ret();
1132 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth;
1133 iNewJitLenth = a.getCodeSize();
1134 }
1135 else if (g_tagIAT[i].bType == 7) //EDI
1136 {
1137 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4;
1138 a.push(ebx);
1139 a.push(ebx);
1140 a.push(ebx);
1141 a.push(esi);
1142 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6);
1143 a.mov(esi, g_iImageBase);//程序基址 后续会将这个位置添加到重定位块处,运行时即变为程序基址了
1144 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode开始的位置+当前jit长度 再往回4字节 即为存放基址的位置
1145 a.lea(ebx, dword_ptr(ebx, esi));
1146 a.mov(dword_ptr(esp, 0xC), ebx);//当前指令所在RVA+6+程序基址 =返回地址
1147 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr);
1148 a.lea(ebx, dword_ptr(ebx, esi));
1149 a.mov(ebx, dword_ptr(ebx));
1150 a.mov(dword_ptr(esp, 0x8), ebx);//代替原函数地址的地址
1151 a.pop(esi);
1152 a.pop(ebx);
1153 a.pop(edi);
1154 a.ret();
1155 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth;
1156 iNewJitLenth = a.getCodeSize();
1157 }
1158 else if (g_tagIAT[i].bType == 8) //Call
1159 {
1160 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4;
1161 a.push(ebx);
1162 a.push(ebx);
1163 a.push(ebx);
1164 a.push(esi);
1165 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr);
1166 a.mov(esi, g_iImageBase);//程序基址 后续会将这个位置添加到重定位块处,运行时即变为程序基址了
1167 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode开始的位置+当前jit长度 再往回4字节 即为存放基址的位置
1168 a.lea(ebx, dword_ptr(ebx, esi));
1169 a.mov(ebx, dword_ptr(ebx));
1170 a.mov(dword_ptr(esp, 8), ebx);//存放目标函数地址的地址的RVA
1171 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6);//返回地址RVA
1172 a.lea(ebx, dword_ptr(ebx, esi));
1173 a.mov(dword_ptr(esp, 0xC), ebx);
1174 a.pop(esi);
1175 a.pop(ebx);
1176 a.ret();
1177 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth;
1178 iNewJitLenth = a.getCodeSize();
1179 }
1180 else if (g_tagIAT[i].bType == 9) //JMP
1181 {
1182 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4;
1183 a.push(ebx);
1184 a.push(ebx);
1185 a.push(ebx);
1186 a.push(esi);
1187 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr);
1188 a.mov(esi, g_iImageBase);//程序基址 后续会将这个位置添加到重定位块处,运行时即变为程序基址了
1189 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode开始的位置+当前jit长度 再往回4字节 即为存放基址的位置
1190 a.lea(ebx, dword_ptr(ebx, esi));
1191 a.mov(dword_ptr(esp,4), 0x3535);//填充垃圾数据
1192 a.mov(ebx, dword_ptr(ebx));
1193 a.mov(dword_ptr(esp, 0xC), ebx);//存放目标函数地址的地址的RVA
1194 a.pop(esi);
1195 a.pop(ebx);
1196 a.pop(ebx);
1197 a.ret();
1198 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth;
1199 iNewJitLenth = a.getCodeSize();
1200 }
1201 else if (g_tagIAT[i].bType == 10) //PUSH
1202 {
1203 g_tagIAT[i].dwNewIatAddr = iNewSectionFileMapAddr + iAddIatLenth + g_tagIAT[i].wIndex * 4;
1204 a.push(ebx);
1205 a.push(ebx);
1206 a.push(ebx);
1207 a.push(esi);
1208 a.mov(ebx, (int)g_tagIAT[i].dwNewIatAddr);
1209 a.mov(esi, g_iImageBase);//程序基址 后续会将这个位置添加到重定位块处,运行时即变为程序基址了
1210 g_tagIAT[i].dwRelocAddr = iNewJitBeginAddrRva + a.getCodeSize() - 4;//shellcode开始的位置+当前jit长度 再往回4字节 即为存放基址的位置
1211 a.lea(ebx, dword_ptr(ebx, esi));
1212 a.mov(ebx, dword_ptr(ebx));
1213 a.mov(dword_ptr(esp, 0xC), ebx);//存放目标函数地址的地址的RVA
1214 a.mov(ebx, (int)g_tagIAT[i].dwCallAddr + 6); //返回地址RVA
1215 a.lea(ebx, dword_ptr(ebx, esi));
1216 a.mov(dword_ptr(esp, 8), ebx);
1217 a.pop(esi);
1218 a.pop(ebx);
1219 a.ret();
1220 g_tagIAT[i].dwJmpAddr = iNewJitBeginAddrRva + iNewJitLenth;
1221 iNewJitLenth = a.getCodeSize();
1222 }
1223 }
1224 a.bind(LoadDllOver);//加载函数地址表以及构建替代IAT的ShellCode完成
1225 a.mov(edi, dword_ptr(ebp, 8));//获得基址
1226 for (int i = 0; i < g_tagIAT.size(); i++)
1227 {
1228 a.lea(ecx, dword_ptr(edi, g_tagIAT[i].dwCallAddr));
1229 a.mov(byte_ptr(ecx), 0xE9);
1230 //由于这里的E9后面的值,是偏移,所以不用加上基址。偏移量=目标地址-当前指令地址-指令长度
1231 a.mov(dword_ptr(ecx, 1), (int)(g_tagIAT[i].dwJmpAddr - g_tagIAT[i].dwCallAddr - 5));
1232 if (g_tagIAT[i].bType == 0)
1233 {
1234 continue;
1235 }
1236 a.mov(byte_ptr(ecx, 5), 0x90);
1237 }
1238 a.add(esp, 0x10);//8+8
1239 a.pop(ebx);
1240 a.popa();
1241 a.ret();
1242
1243 PVOID szJit = a.make();
1244 int iJitLenth = a.getCodeSize();
1245 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iAddIatLenth + iLoadIatLenth + iJitLenth);
1246 memcpy(g_pFileSrc + g_iFileSize + iAddIatLenth + iLoadIatLenth , szJit, iJitLenth);
1247
1248
1249 //一共增加的代码=IAT相关数据+加载后的函数地址表大小+JIT代码长度
1250 int iAddSrcLen = iAddIatLenth + iLoadIatLenth + iJitLenth;
1251 //完善节长度等数据 保守起见重新获取节表信息
1252 pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc;
1253 pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew);
1254 pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader);
1255 pSection += pNtHead->FileHeader.NumberOfSections - 1;
1256 if (!(iAddSrcLen%g_iFileAlignment))
1257 {
1258 pSection->SizeOfRawData = iAddSrcLen;
1259 }
1260 else
1261 {
1262 pSection->SizeOfRawData = iAddSrcLen + g_iFileAlignment - (iAddSrcLen%g_iFileAlignment);
1263 }
1264 if (!(iAddSrcLen%g_iSectionAlignment))
1265 {
1266 pSection->Misc.VirtualSize = iAddSrcLen;
1267 }
1268 else
1269 {
1270 pSection->Misc.VirtualSize = iAddSrcLen + g_iSectionAlignment - (iAddSrcLen%g_iSectionAlignment);
1271 }
1272 pNtHead->OptionalHeader.SizeOfImage += pSection->Misc.VirtualSize;
1273
1274 if (iAddSrcLen != pSection->SizeOfRawData)//当新增长度与对齐后的节长度不相等时,将其补全
1275 {
1276 int iLenth = pSection->SizeOfRawData;//先保存,以免扩容后原地址被回收
1277 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iLenth);
1278 memset(g_pFileSrc + g_iFileSize + iAddSrcLen, 0, iLenth - iAddSrcLen);
1279 }
1280 g_iFileSize += pSection->SizeOfRawData;
1281
1282
1283
1284 //将原重定位中 涉及IAT的重定位项删掉
1285 //1.先统计IAT中的地址位置代码(除了mov eax的地址位置在指令位置+1处,其他皆为+2)
1286 vector<WORD>vDeleteIatAddr;//需要删除的重定位信息
1287 for (int i = 0; i < g_tagIAT.size(); i++)
1288 {
1289 if (g_tagIAT[i].bType==0) //mov eax 重定位地址位于调用地址+1处
1290 {
1291 vDeleteIatAddr.push_back(g_tagIAT[i].dwCallAddr + 1);
1292 }
1293 else
1294 {
1295 vDeleteIatAddr.push_back(g_tagIAT[i].dwCallAddr + 2);
1296 }
1297
1298 }
1299
1300 //2.统计出重定位表有几个重定位块,每个块的基址是多少,里面有多少个偏移
1301 for (int i = 0; i < iRelocationLenth; i++)
1302 {
1303 tagRelocation addR;
1304 addR.wR_Head = *(int*)(szR_Src + i);
1305 int iR_Lenth = *(int*)(szR_Src + i + 4);
1306 for (int j = 8; j < iR_Lenth; j+=2)
1307 {
1308 WORD ccc = *(WORD*)(szR_Src + i + j);
1309 addR.wR_Offset.push_back(ccc);
1310 }
1311 vOldReloction.push_back(addR);
1312 i += iR_Lenth - 1;
1313 }
1314
1315 //3.根据IAT里的地址,在重定位地址表查找,找到之后将其删除
1316 for (int i = 0; i < vDeleteIatAddr.size(); i++)
1317 {
1318 for (int j = 0; j < vOldReloction.size(); j++)
1319 {
1320 if ((vDeleteIatAddr[i] & 0xFFF000) > vOldReloction[j].wR_Head) //当调用地址的重定位块大于当前重定位表块时
1321 {
1322 continue;
1323 }
1324 else if ((vDeleteIatAddr[i] & 0xFFF000) < vOldReloction[j].wR_Head)
1325 {
1326 break;
1327 }
1328 else //找到对应重定位块
1329 {
1330 for (int k = 0; k < vOldReloction[j].wR_Offset.size(); k++)
1331 {
1332 if ((vDeleteIatAddr[i] & 0xFFF) == (vOldReloction[j].wR_Offset[k] & 0xFFF))
1333 {
1334 vOldReloction[j].wR_Offset.erase(vOldReloction[j].wR_Offset.begin() + k);
1335 goto NextIatAddr;
1336 }
1337 }
1338 }
1339
1340 }
1341 NextIatAddr:;
1342 }
1343
1344 //4.对齐重定位表数据,
1345 /*如果重定位块中项目为偶数个,则跳过
1346 如果是奇数个,看最后一个是否为0。如果为0,删掉;如果不为0,补0*/
1347 for (int i = 0; i < vOldReloction.size(); i++)
1348 {
1349 int iReloctionNum = vOldReloction[i].wR_Offset.size();
1350 if (iReloctionNum % 2) //取余 如果能取到 说明为奇数
1351 {
1352 if (vOldReloction[i].wR_Offset[iReloctionNum-1] == 0)
1353 {
1354 vOldReloction[i].wR_Offset.pop_back();
1355 }
1356 else
1357 {
1358 vOldReloction[i].wR_Offset.push_back(0);
1359 }
1360 }
1361 }
1362
1363 //恢复重定位表
1364 szR_Src = NULL;
1365 iRelocationLenth = 0;
1366 for (int i = 0; i < vOldReloction.size(); i++)
1367 {
1368 szR_Src = (char*)realloc(szR_Src, iRelocationLenth + 8);
1369 memcpy(szR_Src + iRelocationLenth, &vOldReloction[i].wR_Head, 4);
1370 int iR_Lenth = vOldReloction[i].wR_Offset.size() * 2 + 8;
1371 memcpy(szR_Src + iRelocationLenth + 4, &iR_Lenth, 4);
1372 iRelocationLenth += 8;
1373 for (int j = 0; j < vOldReloction[i].wR_Offset.size(); j++)
1374 {
1375 szR_Src = (char*)realloc(szR_Src, iRelocationLenth + 8 + j*2);
1376 memcpy(szR_Src + iRelocationLenth + j*2, &vOldReloction[i].wR_Offset[j], 2);
1377 }
1378 iRelocationLenth += vOldReloction[i].wR_Offset.size() * 2 ;
1379 }
1380
1381
1382 //增加新的重定位项
1383 char *szAddRelocSrc = NULL; //总新增重定位数据
1384 char *szNowAddrelocSrc = NULL;//子新增重定位数据
1385 int iAddRelocLen = 0; //总重定位数据长度
1386 int iNowAddRelocLen = 0; //子重定位数据长度
1387
1388 int iPage = 0; //页大小
1389 int iPageOffset = 0; //页内偏移
1390
1391
1392 //先增加新OEP用于求得基址的重定位项
1393 iNowAddRelocLen = 10; //子长度
1394 szNowAddrelocSrc = (char*)malloc(iNowAddRelocLen);//子数据
1395 iPage = (g_iNewOEP + 1) & 0xfff000; //PUSH 0000 0000 重定位数据为地址 偏移+1
1396 iPageOffset = ((g_iNewOEP + 1) & 0xfff) | 0x3000;
1397 memcpy(szNowAddrelocSrc, &iPage, 4);//页偏移
1398 memcpy(szNowAddrelocSrc + 4, &iNowAddRelocLen, 4);//页大小
1399 memcpy(szNowAddrelocSrc + 8, &iPageOffset, 2);
1400
1401 //开始新增shellcode中的重定位项
1402 for (int i = 0; i < g_tagIAT.size(); i++)
1403 {
1404 if (iPage == ((g_tagIAT[i].dwRelocAddr) & 0xfff000)) //判断是否与当前页大小一致
1405 {
1406 szNowAddrelocSrc = (char*)realloc(szNowAddrelocSrc, iNowAddRelocLen + 2);
1407 iPageOffset = (g_tagIAT[i].dwRelocAddr & 0xfff) | 0x3000;
1408 memcpy(szNowAddrelocSrc + iNowAddRelocLen, &iPageOffset, 2);
1409 iNowAddRelocLen += 2;
1410 memcpy(szNowAddrelocSrc + 4, &iNowAddRelocLen, 4);//页大小
1411 }
1412 else //开启新页
1413 {
1414 if ((iNowAddRelocLen % 4)) //是否4字节对齐
1415 {
1416 szNowAddrelocSrc = (char*)realloc(szNowAddrelocSrc, iNowAddRelocLen + 2);
1417 memset(szNowAddrelocSrc + iNowAddRelocLen, 0, 2);
1418 iNowAddRelocLen += 2;
1419 memcpy(szNowAddrelocSrc + 4, &iNowAddRelocLen, 4);//页大小
1420 }
1421
1422 szAddRelocSrc = (char*)realloc(szAddRelocSrc, iAddRelocLen + iNowAddRelocLen);//将总重定位数据扩容
1423 memcpy(szAddRelocSrc + iAddRelocLen, szNowAddrelocSrc, iNowAddRelocLen); //复制子重定位块到总重定位块中
1424 iAddRelocLen += iNowAddRelocLen; //更新总重定位块大小
1425
1426 iNowAddRelocLen = 10;
1427 szNowAddrelocSrc = (char*)malloc(iNowAddRelocLen);//子数据
1428 iPage = g_tagIAT[i].dwRelocAddr & 0xfff000;
1429 iPageOffset = (g_tagIAT[i].dwRelocAddr & 0xfff) | 0x3000;
1430 memcpy(szNowAddrelocSrc, &iPage, 4);//页偏移
1431 memcpy(szNowAddrelocSrc + 4, &iNowAddRelocLen, 4);//页大小
1432 memcpy(szNowAddrelocSrc + 8, &iPageOffset, 2);
1433 }
1434 }
1435 //此时 由于已经遍历到tagIAT结构最后 但当前重定位块并为添加到总重定位块中,故需要再进行填充
1436 if ((iNowAddRelocLen % 4)) //是否4字节对齐
1437 {
1438 szNowAddrelocSrc = (char*)realloc(szNowAddrelocSrc, iNowAddRelocLen + 2);
1439 memset(szNowAddrelocSrc + iNowAddRelocLen, 0, 2);
1440 iNowAddRelocLen += 2;
1441 memcpy(szNowAddrelocSrc + 4, &iNowAddRelocLen, 4);//页大小
1442 }
1443
1444 szAddRelocSrc = (char*)realloc(szAddRelocSrc, iAddRelocLen + iNowAddRelocLen);//将总重定位数据扩容
1445 memcpy(szAddRelocSrc + iAddRelocLen, szNowAddrelocSrc, iNowAddRelocLen); //复制子重定位块到总重定位块中
1446 iAddRelocLen += iNowAddRelocLen; //更新总重定位块大小
1447
1448
1449 if ((iR_FileLenth - iRelocationLenth) < iAddRelocLen) //节表长度和实际数据长度是否足够填充新的重定位块
1450 {
1451 //扩充重定位数据
1452 //整数取余 = (新增数据总大小- 之前剩余空间间隙)%对齐大小
1453 int iZeroLenth = (iAddRelocLen - (iR_FileLenth - iRelocationLenth)) % g_iFileAlignment;
1454 if (iZeroLenth)
1455 {
1456 iR_FileLenth = iRelocationLenth + iAddRelocLen + g_iFileAlignment - iZeroLenth;
1457 }
1458 else
1459 {
1460 iR_FileLenth = iRelocationLenth + iAddRelocLen;
1461 }
1462 szR_Src = (char*)realloc(szR_Src, iR_FileLenth);
1463 memcpy(szR_Src + iRelocationLenth, szAddRelocSrc, iAddRelocLen);
1464 memset(szR_Src + iRelocationLenth + iAddRelocLen, 0, iR_FileLenth - iRelocationLenth - iAddRelocLen);
1465 }
1466 else
1467 {
1468 szR_Src = (char*)realloc(szR_Src, iR_FileLenth);
1469 memcpy(szR_Src + iRelocationLenth, szAddRelocSrc, iAddRelocLen);
1470 iRelocationLenth += iAddRelocLen;
1471 memset(szR_Src + iRelocationLenth, 0, iR_FileLenth - iRelocationLenth);
1472 }
1473
1474 //还原重定位
1475 g_pFileSrc = (UCHAR*)realloc(g_pFileSrc, g_iFileSize + iR_FileLenth);
1476 memcpy(g_pFileSrc + g_iFileSize, szR_Src, iR_FileLenth);
1477 g_iFileSize += iR_FileLenth;
1478
1479 ////直接用realloc又抽风 用其他转移吧
1480 //char *szCopyBuff = (char*)malloc(g_iFileSize + iR_FileLenth);
1481 //memcpy(szCopyBuff, g_pFileSrc, g_iFileSize);
1482 //memcpy(szCopyBuff + g_iFileSize, szR_Src, iR_FileLenth);
1483 //g_iFileSize += iR_FileLenth;
1484 //memcpy(g_pFileSrc, szCopyBuff, g_iFileSize);
1485
1486
1487 pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc;
1488 pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew);
1489 pSection = (PIMAGE_SECTION_HEADER)((DWORD)&pNtHead->OptionalHeader + pNtHead->FileHeader.SizeOfOptionalHeader);
1490 pSection += pNtHead->FileHeader.NumberOfSections - 1;
1491 int iR_FileAddr = pSection->PointerToRawData + pSection->SizeOfRawData;
1492 int iR_MapAddr = 0;
1493 if (!(pSection->Misc.VirtualSize % g_iSectionAlignment))
1494 {
1495 iR_MapAddr = pSection->VirtualAddress + pSection->Misc.VirtualSize;
1496 }
1497 else
1498 {
1499 iR_MapAddr = pSection->VirtualAddress + pSection->Misc.VirtualSize
1500 + g_iSectionAlignment - (pSection->Misc.VirtualSize % g_iSectionAlignment);
1501 }
1502
1503 pSection++;
1504 strcpy((char*)pSection->Name, szR_Name);
1505 pSection->Characteristics = (0x20000000 | 0x40000000 | 0x80000000 | 0x40);
1506 pSection->VirtualAddress = iR_MapAddr;
1507 pSection->Misc.VirtualSize = iR_FileLenth;
1508 pSection->PointerToRawData = iR_FileAddr;
1509 pSection->SizeOfRawData = iR_FileLenth;
1510 pNtHead->OptionalHeader.DataDirectory[5].VirtualAddress = iR_MapAddr;
1511 pNtHead->OptionalHeader.DataDirectory[5].Size = iRelocationLenth;
1512 pNtHead->FileHeader.NumberOfSections += 1;
1513 if (!(iR_FileLenth%g_iSectionAlignment))
1514 {
1515 pNtHead->OptionalHeader.SizeOfImage += iR_FileLenth;
1516 }
1517 else
1518 {
1519 pNtHead->OptionalHeader.SizeOfImage += iR_FileLenth + g_iSectionAlignment - (iR_FileLenth%g_iSectionAlignment);
1520 }
1521
1522 }
1523 return true;
1524 }
1525
1526
1527
1528 int main()
1529 {
1530 //"C:\\Users\\Admin\\Desktop\\弹窗.exe
1531 char FileName[] = { "C:\\Users\\Admin\\Desktop\\弹窗.exe" };
1532 if (!LoadFile(FileName))
1533 {
1534 cout << "文件打开失败" << endl;
1535 system("pause");
1536 return -1;
1537 }
1538
1539 if (!CheckPE())
1540 {
1541 cout << "该程序不是PE文件" << endl;
1542 system("pause");
1543 return -1;
1544 }
1545
1546 if (!FindCodeAddr()) //找到对应调用IAT的地址
1547 {
1548 cout << "该程序没有导入表,请检查" << endl;
1549 system("pause");
1550 return -1;
1551 }
1552
1553 if (!SaveDll())
1554 {
1555 cout << "保存DLL信息失败" << endl;
1556 system("pause");
1557 return -1;
1558 }
1559
1560 if (!NewIat())
1561 {
1562 cout << "新建IAT表失败" << endl;
1563 system("pause");
1564 return -1;
1565 }
1566
1567 //C:\\Users\\Admin\\Desktop\\弹窗IAT加密测试.exe
1568 char NewFilePath[] = "C:\\Users\\Admin\\Desktop\\弹窗IAT加密测试.exe";
1569 HANDLE hNewFile = CreateFileA(NewFilePath,
1570 GENERIC_READ | GENERIC_WRITE,
1571 FILE_SHARE_READ | FILE_SHARE_WRITE,
1572 NULL,
1573 CREATE_ALWAYS, //创建并覆盖上一个文件
1574 FILE_ATTRIBUTE_ARCHIVE,
1575 NULL);
1576
1577 if (hNewFile == INVALID_HANDLE_VALUE)
1578 {
1579 printf("文件保存失败\n");
1580 int iError = GetLastError();
1581 return 1;
1582 }
1583
1584 LPDWORD iNum = NULL;
1585 WriteFile(hNewFile, g_pFileSrc, g_iFileSize, iNum, NULL); //写入文件
1586 CloseHandle(hNewFile);
1587 char *NewFileName1 = strrchr(NewFilePath, '\\') + 1;
1588 char *NewFileName = strtok(NewFileName1, ".");
1589 MessageBoxA(0, NewFileName, "加密成功", 0);
1590 MessageBoxA(0, "by:阿怪\n 2020.12.26", "IAT加密", 0);
1591
1592 system("pause");
1593 }
IAT加密相对于代码段加密较为复杂,特别是在自己实现获得函数地址,以及创建对应的shellcode,并把原调用指令全部一一修改的流程较为繁琐,需要用到各种变量记录位置。博主也是刚接触到这块的新手小白,如果有疑惑或者说的不对的地方欢迎在评论指出,互相学习。感谢!!
浅谈IAT加密原理及过程的更多相关文章
- 【推荐】JAVA基础◆浅谈3DES加密解密
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- 浅谈 PHP 神盾的解密过程
原文:浅谈 PHP 神盾的解密过程 前些日子一个朋友丢了个shell给我,让我帮忙解密,打开源码看了下写着是 “神盾加密” , 牛逼闪闪的样子.百度下发现神盾是个很古老的东西,最后一次更新是在 201 ...
- 【ASP.NET MVC系列】浅谈ASP.NET 程序发布过程
ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...
- 浅谈React工作原理
浅谈React工作原理:https://www.cnblogs.com/yikuu/p/9660932.html 转自:https://cloud.tencent.com/info/63f656e0b ...
- 【ASP.NET MVC系列】浅谈ASP.NET MVC运行过程
ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...
- 浅谈html运行原理
浅谈HTML运行原理,所谓的HTML简单的来说就是一个网页,虽然第一节就讲html原理可能大家会听不懂,就当是给一个初步印象把,至少大概知道一个网页的运行流程是怎样的,下面上一张图: 大致的一个htm ...
- HTTPS加密原理与过程
HTTPS加密原理与过程 HTTP 超文本传输协议一种属于应用层的协议 缺点: 通信使用明文(不加密),内容可能会被窃听 不验证通信方的身份,因此有可能遭遇伪装 无法证明报文的完整性,所以有可能已遭篡 ...
- 浅谈JVM编译原理->.java文件转变为.class文件的过程
为什么需要编译? 我们平常写代码,有规范的命名方式,都能够看得懂,但是我们写的代码计算机是看不懂的,所以需要编译,也就是一个转换的过程,如下: 1.这个是咱们平时写的代码,就比较好理解,对人友好 2. ...
- [iOS]浅谈NSRunloop工作原理和相关应用
一. 认识NSRunloop 1.1 NSRunloop与程序运行 那么具体什么是NSRunLoop呢?其实NSRunLoop的本质是一个消息机制的处理模式.让我们首先来看一下程序的入口——main ...
随机推荐
- 下载centos镜像的地址
- 发现了一个关于 gin 1.3.0 框架的 bug
gin 1.3.0 框架 http 响应数据错乱问题排查 问题概述 客户端同时发起多个http请求,gin接受到请求后,其中一个接口响应内容为空,另外一个接口响应内容包含接口1,接口2的响应内容,导致 ...
- dubbo源码学习(一)dubbo容器启动流程简略分析
最近在学习dubbo,dubbo的使用感觉非常的简单,方便,基于Spring的容器加载配置文件就能直接搭建起dubbo,之前学习中没有养成记笔记的习惯,时间一久就容易忘记,后期的复习又需要话费较长的时 ...
- 基于CefSharp开发(三)浏览器头部优化
一.上文回顾 上编实现了简单的网页加载功能包括URL输入.打开空标签页.网页链接中新页面处理等 本编将对网页的Title绑定.前进.后退.刷新等事件处理 二.Title绑定处理 当打开网页时Title ...
- PyQt(Python+Qt)学习随笔:Model/View架构中的Model模型概念
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 Model/View架构中的Model模型Model与数据源通信,为体系结构中的其他组件提供数据接口 ...
- PyQt学习随笔:槽函数获取信号发送对象的方法
在PyQt中,相似控件发送的信号可以每个控件信号对应一个槽函数,也可以将相似控件的相同信号对应到一个槽函数,但如果槽函数相同,怎么区分信号是谁发送的呢?那就是在信号函数中使用sender()函数获取信 ...
- 第15.18节 PyQt(Python+Qt)入门学习:Model/View架构中视图Item Views父类详解
老猿Python博文目录 老猿Python博客地址 一.概述 在PyQt图形界面中,支持采用Model/View架构实现数据和界面逻辑分离,其中Model用于处理数据存储,View用于界面数据展现,当 ...
- 第三篇 Scrum 冲刺博客
一.站立式会议 1. 会议照片 2. 工作汇报 团队成员名称 昨日(24日)完成的工作 今天(25日)计划完成的工作 工作中遇到的困难 陈锐基 - 个人信息编辑后与组件关联- 表白墙数据用 Vuex ...
- html标签学习1
html:超文本标记语言 超文本标记语言的结构包括"头"部分(英语:Head).和"主体"部分(英语:Body),其中"头"部提供关于网页的 ...
- js日期格式化-----总结
1. // 对Date的扩展,将 Date 转化为指定格式的String // 月(M).日(d).小时(h).分(m).秒(s).季度(q) 可以用 1-2 个占位符, // 年(y)可以用 1-4 ...