<<目录>>
0.前言
1.什么是重定位模块
2.重定位模块的原理
2-1.重定位模块的设计
2-2.重定位模块何时插入
2-3.修复内存跳转
2-4.指令的变换
2-5.重定位模块的缺陷
2-6.重定位模块演示
3.重定位模块的应用
4.后语
正文ing >>>
0.前言
这篇文章也拖的比较长了,由于重定位模块需要反汇编引擎的支持,上一次写的反汇编引擎有N多BUG。所以一直在调试,期间又遇上XCON和XKUNGFOO的召开。我的议题是讨论病毒感染策略,其中详细讲解了代码集成这一感染策略。因为BLACK HAT的大牛有事情没有来。所以本来在XKUNGFOO上的议题给我转到XCON上进行讨论。期间我对重定位模块进行了一个演示,算是一个“婴儿”版吧。这之后我会对这个引擎进行一个长期的打磨,争取可以为更多的病毒CODER和壳CODER们有所帮助。
1.什么是重定位模块
重定位模块的产生,首先是在95年的ZMIST病毒的代码集成感染提出的。目的是将病毒代码随机分片插入到宿主文件代码中,并用跳转指令连接。如果插入的位置是在跳转指令之中,会对跳转的偏移进行改变,所以需要使用重定义模块进行对偏移的修复,以便于可以使感染后的程序继续的执行。然而重定位模块的作用并不只限于感染方面,例如花指令构造器以及高级的变形引擎中都可以得到很好的应用,在壳方面的应用在于如果我们把壳的引导代码以代码集成方式进行感染,破解者很难区分壳与真正的代码段,防止DUMP等。
2.重定位模块的原理
2-1.重定位模块的设计
重定位模块是整个代码集成的关键模块。它依靠反汇编引擎来识别代码。并且也负责修订病毒体偏移的任务。
先读取代码节,以代码节的各个跳转指令为节点进行分段。记录它的偏移长度以及跳转方向。
分析跳转指令之间产生的空隙。按空隙的大小对要插入的代码进行分段。
在跳转中插入代码后,修订跳转的偏移量
2-2.重定位模块何时插入
在将病毒代码插入到宿主代码中最理想的位置是两段跳转指令之间,这样可以不用修复任何跳转偏移。
修复偏移只有在插入到跳转指令的集合内,如果有跳转指令有交集则修复所有跳转指令的偏移。
2-3.修复内存跳转
在遇到如call dword ptr [404340],jmp dword ptr [404340]等代码,需要拆解ModRM,SIB两个位得到。由于call,jmp由内存指定值跳转的编码同为FF,扩展编码为call:02,jmp:04。由于我们编写的病毒在32位下运行,所以16位的编码不进行考虑。
查INTEL手册编码得到两组可以跳转的情况。
单ModRm情况:当为call,ModRM取15h,为jmp,ModRM取25h.
具有SIB的情况:Mod为00h.查看R/M为04h RO为2或者4,所以得下两种情况ModRM为14h,24h。检查SIB,SIB的情况仅与Index,Base字段有关。当Index = 04h,Base = 05h下的情况全部可以重定位。
从指向的内存中取出要跳转的地址,进行偏移修复。
2-4.指令的变换
某些跳转指令的立即数是单字节,这些指令无论向上还是向跳转的空间只有127个字节,所以当插入代码长度与偏移的和大于这个数字时就要利用相同作用但偏移量更大的指令替换。在扩展指令后,指令的长度进行了增大,这时如果此指令在其他跳转集合内需要再进行一次重定位修复。
2-5.重定位模块的缺陷
重定位模块只能修订以偏移量作为跳转情况 如果是动态跳转例如:
Jmp dword ptr [ebx]
Call eax
等类似的代码重定位模块则不能修复。
2-6.重定位模块演示
这里我们定义:
原始代码为:O
要插入的代码:I 将I代码分为I1,I2,I3三段代码
O的代码
Start: jmp ZZZ mov eax, 1 std jo XXX rep movsb call Call1 ZZZ: mov ebx, 2 mov ecx, 3 mov edx, 4 Data: db 0FFh,025h,86h,10h,40h,00h GGG: call Call2 mov eax, 1 mov eax, 1 call GGG mov ebx, 2 XXX: mov eax, 1 mov ebx, 2 mov ecx, 3 jz Start mov edx, 4 jz Start mov eax, 1 mov ebx, 2 jmp ZZZ mov ecx, 3 mov edx, 4 call XXX Exit: invoke ExitProcess, 1 retn 00h Call1 proc mov eax, 1 ret Call1 endp Call2 proc mov eax, 2 ret Call2 endp db 79h,010h,040h,00h end Start
以上的代码是我随手键入的,包括了需要重定位的几个方面
以下是I1-3的三段要插入的代码
InsertStart1: push eax mov eax, 1 sub eax, 0FFh mov eax, 1 sub eax, 0FFh mov eax, 1 pop eax InsertStart2: push ebx mov ebx, 0FFFFFFFFh sub ebx, 010h pop ebx InsertStart3: push ecx mov ecx, 0FFFFFFFFh sub ecx, 010h pop ecx
以上代码也是我随手键入的。我们的目的是将I1-3插入到O中,并且O可以得到正常的运行。
插入的位置为:第1,15,30语句之后进行插入。这些位置都是我随机键入的。
O的反汇编代码如图1所示:

将I1-I3插入后的代码


从图中可以看到虽然代码进行插入,但是程序的偏移进行经过了修复。
3.重定位模块的应用
重定位模块可以在感染策略,花指令构造,变形引擎方面得到很好的应用。高级病毒与壳必备模块。
4.后语
重定位模块的编译需要反汇编引擎的支持,调试过后的反汇编引擎代码从反汇编引擎构建的文章中下载,我重新传代码上去了。重定位引擎的代码在这篇中下载。希望不要拿它去做邪恶的东东。模块可能有很多BUG。单我一个人的能力是测试不出那么多BUG的。希望有志同道合的朋友帮忙测试完善。
这里给出一个使用例子
.const g_szTarget db 'vius_lib.exe',0 ;; ---------------------------------------- ;; data segment ;; ---------------------------------------- .data g_hFile dd 0 g_hMap dd 0 g_pMem dd 0 g_dwTargetSize dd 0 g_TargetCodeDraw CODEDRAW <0> ;; ---------------------------------------- ;; code segment ;; ---------------------------------------- .code Start: invoke OutputDebugString, CTXT("Entry") lea eax, g_TargetCodeDraw invoke InitCodeDraw, eax mov edi, eax invoke OutputDebugString, CTXT("Map File") lea edi, g_TargetCodeDraw assume edi : ptr CODEDRAW lea eax, g_szTarget lea ecx, g_hFile lea edx, g_hMap lea ebx, g_pMem invoke MapFile2MemNotClose, eax, 0, ecx, edx, ebx .if eax == 0 jmp Exit_HME .endif mov g_dwTargetSize, eax assume edi : ptr CODEDRAW invoke AllocMemory, MAX_LDISLENGTH mov dword ptr [edi].LengthList, eax mov eax, sizeof CODEFRAME * MAX_CODEFRAME invoke AllocMemory, eax mov dword ptr [edi].CodeFrame, eax mov eax, sizeof INSERTFRAME * MAX_INSERTFRAME invoke AllocMemory, eax mov dword ptr [edi].InsertFrame, eax invoke OutputDebugString, CTXT("Alloc memory for exchange buffer") ;; alloc memory for exchange buffer mov dword ptr [edi].MaxExchange, eax invoke AllocMemory, eax mov dword ptr [edi].ExchangeBuf, eax ;; init relocater invoke OutputDebugString, CTXT("Init relocater") mov eax, g_pMem mov dword ptr [edi].dwMapBase, eax invoke OutputDebugString, CTXT("Count Jmp") invoke InitLRelocater, edi invoke PrintCodeDraw, edi ;; insert invoke OutputDebugString, CTXT("Insert") invoke GetCurrentPosition, edi, 1 mov edx, eax lea eax, g_TargetCodeDraw lea ebx, InsertStart1 mov ecx, offset InsertStart2 - offset InsertStart1 invoke LRelocateInserter, eax, edx, ebx, ecx invoke GetCurrentPosition, edi, 15 mov edx, eax lea eax, g_TargetCodeDraw lea ebx, InsertStart2 mov ecx, offset InsertStart3 - offset InsertStart2 invoke LRelocateInserter, eax, edx, ebx, ecx invoke GetCurrentPosition, edi, 30 mov edx, eax lea eax, g_TargetCodeDraw lea ebx, InsertStart3 mov ecx, offset InsertStart4 - offset InsertStart3 invoke LRelocateInserter, eax, edx, ebx, ecx ;; free memory invoke OutputDebugString, CTXT("Free memory") ;invoke UnMapMemory, g_pMem lea eax, g_hFile lea ebx, g_hMap lea edx, g_pMem invoke FreeFileMemory, eax, ebx, edx lea edi, g_TargetCodeDraw assume edi : ptr CODEDRAW mov eax, dword ptr [edi].LengthList invoke FreeMemory, eax mov eax, dword ptr [edi].CodeFrame invoke FreeMemory, eax mov eax, dword ptr [edi].InsertFrame invoke FreeMemory, eax mov eax, dword ptr [edi].ExchangeBuf invoke FreeMemory, eax assume eax : nothing assume edi : nothing jmp Exit InsertStart1: push eax mov eax, 1 sub eax, 0FFh mov eax, 1 sub eax, 0FFh mov eax, 1 pop eax InsertStart2: push ebx mov ebx, 0FFFFFFFFh sub ebx, 010h pop ebx InsertStart3: push ecx mov ecx, 0FFFFFFFFh sub ecx, 010h pop ecx InsertStart4: Exit: invoke OutputDebugString, CTXT("Exit") invoke ExitProcess, 01h
PrintCodeDraw proc uses ebx ecx edx esi edi pCodeDraw : LPVOID LOCAL dwCount : DWORD mov dwCount, 0 mov edi, pCodeDraw assume edi : ptr CODEDRAW invoke crt_printf, CTXT("CodeDraw---") EndLine mov eax, dword ptr [edi].dwInstructionCount invoke crt_printf, CTXT("dwInstructionCount = %X"), eax EndLine mov eax, dword ptr [edi].dwCodeFrameCount invoke crt_printf, CTXT("dwCodeFrameCount = %X"), eax EndLine mov eax, dword ptr [edi].dwInsertFrameCount invoke crt_printf, CTXT("dwInsertFrameCount = %X"), eax EndLine mov eax, dword ptr [edi].dwMapBase invoke crt_printf, CTXT("dwMapBase = %X"), eax EndLine mov eax, dword ptr [edi].dwLoadBase invoke crt_printf, CTXT("dwLoadBase = %X"), eax EndLine mov eax, dword ptr [edi].dwCodeBaseVA invoke crt_printf, CTXT("dwCodeBaseVA = %X"), eax EndLine mov eax, dword ptr [edi].dwCodeMapBase invoke crt_printf, CTXT("dwCodeMapBase = %X"), eax EndLine mov eax, dword ptr [edi].pCodeMapStart invoke crt_printf, CTXT("pCodeMapStart = %X"), eax EndLine mov eax, dword ptr [edi].pCodeMapEnd invoke crt_printf, CTXT("pCodeMapEnd = %X"), eax EndLine mov eax, dword ptr [edi].dwCodeVirtualSize invoke crt_printf, CTXT("dwCodeVirtualSize = %X"), eax EndLine mov eax, dword ptr [edi].dwCodeSizeOfRawData invoke crt_printf, CTXT("dwCodeSizeOfRawData = %X"), eax EndLine mov eax, dword ptr [edi].dwAnalyzeRealSize invoke crt_printf, CTXT("dwAnalyzeRealSize = %X"), eax EndLine mov eax, dword ptr [edi].MaxLengthList invoke crt_printf, CTXT("MaxLengthList = %X"), eax EndLine mov eax, dword ptr [edi].MaxCodeFrame invoke crt_printf, CTXT("MaxCodeFrame = %X"), eax EndLine mov eax, dword ptr [edi].MaxInsertFrame invoke crt_printf, CTXT("MaxInsertFrame = %X"), eax EndLine mov eax, dword ptr [edi].MaxExchange invoke crt_printf, CTXT("MaxExchange = %X"), eax EndLine mov eax, dword ptr [edi].LengthList invoke crt_printf, CTXT("LengthList = %X"), eax EndLine mov eax, dword ptr [edi].CodeFrame invoke crt_printf, CTXT("CodeFrame = %X"), eax EndLine mov eax, dword ptr [edi].InsertFrame invoke crt_printf, CTXT("InsertFrame = %X"), eax EndLine mov eax, dword ptr [edi].ExchangeBuf invoke crt_printf, CTXT("ExchangeBuf = %X"), eax EndLine mov ebx, dword ptr [edi].CodeFrame assume ebx : ptr CODEFRAME PrintCodeDraw_Loop: invoke crt_printf, CTXT("CodeFrames---") EndLine movzx eax, byte ptr [ebx].bJmpCode1 invoke crt_printf, CTXT("bJmpCode1 = %X"), eax EndLine movzx eax, byte ptr [ebx].bJmpCode2 invoke crt_printf, CTXT("bJmpCode2 = %X"), eax EndLine mov eax, dword ptr [ebx].dwJmpCodeLength invoke crt_printf, CTXT("dwJmpCodeLength = %X"), eax EndLine mov eax, dword ptr [ebx].dwCodeLength invoke crt_printf, CTXT("dwCodeLength = %X"), eax EndLine movzx eax, byte ptr [ebx].bJmpType invoke crt_printf, CTXT("bJmpType = %X"), eax EndLine movzx eax, byte ptr [ebx].bDirection invoke crt_printf, CTXT("bDirection = %X"), eax EndLine mov eax, dword ptr [ebx].dwDisplacement invoke crt_printf, CTXT("dwDisplacement = %X"), eax EndLine mov eax, dword ptr [ebx].pStartAddress invoke crt_printf, CTXT("pStartAddress = %X"), eax EndLine mov eax, dword ptr [ebx].pEndAddress invoke crt_printf, CTXT("pEndAddress = %X"), eax EndLine movzx eax, byte ptr [ebx].bNotInsert invoke crt_printf, CTXT("bNotInsert = %X"), eax EndLine movzx eax, byte ptr [ebx].bExpandJmp invoke crt_printf, CTXT("bExpandJmp = %X"), eax EndLine movzx eax, byte ptr [ebx].bInSection invoke crt_printf, CTXT("bInSection = %X"), eax EndLine movzx eax, byte ptr [ebx].bFixPointTo invoke crt_printf, CTXT("bFixPointTo = %X"), eax EndLine mov eax, dword ptr [ebx].dwOrigPointerAddress invoke crt_printf, CTXT("dwOrigPointerAddress = %X"), eax EndLine mov eax, dword ptr [ebx].dwOrigPointToAddress invoke crt_printf, CTXT("dwOrigPointToAddress = %X"), eax EndLine invoke crt_printf, CTXT("----------") EndLine add ebx, sizeof CODEFRAME inc dwCount mov eax, dword ptr [edi].dwCodeFrameCount mov ecx, dwCount cmp ecx, eax jb PrintCodeDraw_Loop Exit_PrintCodeDraw: xor eax, eax assume edi : nothing assume edi : nothing ret PrintCodeDraw endp
新增了一个函数:FixAbsoluteAddress
FixAbsoluteAddress proc uses ebx ecx edx esi edi, pMem : LPVOID, pAlloc : DWORD LOCAL FileInfo : FILEMAPINFO LOCAL Instruction : INSTRUCTION LOCAL dwOldImageBase : DWORD ;; get file info invoke GetFileMapInfoByFileMap, pMem, addr FileInfo mov esi, pMem add esi, dword ptr [esi+03ch] assume esi : ptr IMAGE_NT_HEADERS mov eax, dword ptr [esi].OptionalHeader.ImageBase mov dwOldImageBase, eax lea edi, FileInfo assume edi : ptr FILEMAPINFO mov esi, dword ptr [edi].pCodeBaseVA sub esi, dwOldImageBase add esi, pAlloc mov ecx, dword ptr [edi].dwCodeSizeOfRawData lea edi, Instruction assume edi : ptr INSTRUCTION xor ebx, ebx FixAbsoluteAddress_Loop: invoke LDisEngine, esi, edi add esi, eax add ebx, eax ;; check instruction cmp byte ptr [edi].dwPrefixLength, 0 jnz Continue_FixAbsoluteAddress_Loop cmp byte ptr [edi].bOpcode1, 0FFh jnz Continue_FixAbsoluteAddress_Loop ;; check ModRM mov al, byte ptr [edi].bModRM cmp al, 015h jz FixAbsoluteAddress_HandleAddress cmp al, 025h jz FixAbsoluteAddress_HandleAddress jmp Continue_FixAbsoluteAddress_Loop FixAbsoluteAddress_HandleAddress: mov eax, dword ptr [edi].dwDisplacement sub eax, dwOldImageBase add eax, pAlloc mov dword ptr [esi-4], eax Continue_FixAbsoluteAddress_Loop: cmp ebx, ecx jb FixAbsoluteAddress_Loop Exit_FixAbsoluteAddress: assume esi : nothing assume edi : nothing ret FixAbsoluteAddress endp
这类问题尤其在调用引入表函数中出现严重。---