浅谈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中,里面的指令是在函数运行后修改的。无需重定位了。并在在4.的shellcode中,用到了基址,这里采用的获取基址方式是通过重定位,所以要被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.将新增的节按文件对齐和内存对齐后,将重定位表恢复,恢复起始位置为新增节的起始位置+对齐后的大小
12.IAT加密完成
下面附上代码:
代码长度1594 未精简,有备注 其中有涉及jit编译shellcode指令的代码,所以无法直接复制运行,这里仅提供编写思路。
要在此再增加分析者的难度的话,可以在8.填充导入表信息时,先做异或加密处理,等运行时,再异或解密出来,因为知道位置与长度,所以很容易做到
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=导出表RVA+基址 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,并把原调用指令全部一一修改的流程较为繁琐,需要用到各种变量记录位置。博主也是刚接触到这块的新手小白,如果有疑惑或者说的不对的地方欢迎在评论指出,互相学习。感谢!!