shellcode在C环境下的调用

以启动电脑上的计算器为例,编写ShellCode其实就是两部分,一是获取ShellCode字节码,二是调用它。

获取方式一般是观察代码反汇编和内存相结合:

复制代码
VOID Test()
{
    HMODULE v1 =  LoadLibraryA("kernel32.dll");//0X7778ff70 //WinExec("calc.exe", SW_SHOW); /* 00E31E5E mov esi,esp 00E31E60 push 0E36B30h 00E31E65 call dword ptr ds:[0E3A060h] 00E31E6B cmp esi,esp 00E31E6D call __RTC_CheckEsp (0E3111Dh) 00E31E72 mov dword ptr [v1],ea,0x WinExec("calc.e,0xe", SW_SHOW); 00E31E75 mov esi,esp 00E31E77 push 5 00E31E79 push 0E36B40h 00E31E7E call dword ptr ds:[0E3A064h] 00E31E84 cmp esi,esp 00E31E86 call __RTC_CheckEsp (0E3111Dh) return 0; */ __asm { push ebp; mov ebp, esp; xor eax, eax; push eax; sub esp, 08h; mov byte ptr[ebp - 0Ch], 63h; //c mov byte ptr[ebp - 0Bh], 61h; //a mov byte ptr[ebp - 0Ah], 6Ch; //l mov byte ptr[ebp - 09h], 63h; //c mov byte ptr[ebp - 08h], 2Eh; //. mov byte ptr[ebp - 07h], 65h; //e mov byte ptr[ebp - 06h], 78h; //x mov byte ptr[ebp - 05h], 65h; //e  lea eax, [ebp - 0ch]; push eax; //将calc.exe压入栈内  mov eax, 0x7778ff70; call eax; //调用WinExec  mov esp, ebp; pop ebp; } }
复制代码

然后就是所谓的苦力活,将反汇编中的字节码一个一个抄出来,整合成为一个ShellCode

 

复制代码
CHAR ShellCode[] = {
    0x55,0x8B,0xEC,0x51,0x51,0x83,0x65,0xFC,0x00,0x56,0x57,0xC7,0x45,0xF8,0x63,0x61, 0x6C,0x63,0x64,0xA1,0x18,0x00,0x00,0x00,0x33,0xC9,0x8B,0x40,0x30,0x8B,0x40,0x0C, 0x8B,0x78,0x1C,0x8B,0x3F,0x8B,0x47,0x20,0x66,0x83,0x78,0x10,0x2E,0x74,0x06,0x41, 0x83,0xF9,0x02,0x7C,0xEE,0x8B,0x4F,0x08,0xBA,0xB9,0x6B,0xFF,0xCB,0xE8,0x23,0x00, 0x00,0x00,0x8B,0x4F,0x08,0xBA,0x13,0xB9,0xE6,0x25,0x8B,0xF0,0xE8,0x14,0x00,0x00, 0x00,0x6A,0x01,0x8D,0x4D,0xF8,0x51,0xFF,0xD0,0x6A,0x00,0x6A,0x00,0xFF,0xD6,0x5F, 0x5E,0x8B,0xE5,0x5D,0xC3,0x55,0x8B,0xEC,0x83,0xEC,0x10,0x53,0x56,0x8B,0xF1,0x89, 0x55,0xF0,0x33,0xD2,0x57,0x8B,0x46,0x3C,0x8B,0x5C,0x30,0x78,0x03,0xDE,0x89,0x5D, 0xF4,0x8B,0x4B,0x20,0x03,0xCE,0x39,0x53,0x18,0x76,0x39,0x8B,0x39,0x33,0xC0,0x03, 0xFE,0x8A,0x1F,0x84,0xDB,0x8B,0x5D,0xF4,0x74,0x1C,0x8B,0xD8,0x8A,0x07,0x6B,0xDB, 0x21,0x0F,0xBE,0xC0,0x03,0xD8,0x47,0x8A,0x07,0x84,0xC0,0x75,0xF1,0x89,0x5D,0xF8, 0x8B,0x5D,0xF4,0x8B,0x45,0xF8,0x3B,0x45,0xF0,0x74,0x12,0x83,0xC1,0x04,0x42,0x3B, 0x53,0x18,0x72,0xC7,0x33,0xC0,0x5F,0x5E,0x5B,0x8B,0xE5,0x5D,0xC3,0x8B,0x43,0x24, 0x8D,0x04,0x50,0x0F,0xB7,0x0C,0x30,0x8B,0x43,0x1C,0x8D,0x04,0x88,0x8B,0x04,0x30, 0x03,0xC6,0xEB,0xE2 };
复制代码

对于ShellCode能不能在各个电脑上都适用,我还不敢保证,因为我之前也尝试将别人写的拿过来运行,但是程序崩溃。所以最好自己试着写一遍。

ShellCode字符也可以写成这种形式:

char shellcode[] =
"\x55\x8b\xec\x51\x51\x83\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89"
"\xf3\x8d\x4e\x08\x31\xd2\xcd\x80\xe8\xe4\xff\xff\xff\x2f\x62\x69\x6e" "\x2f\x73\x68\x58"; //...

它利用的是\x的转义字符特性,其实是一样的。

 

写好ShellCode后就该调用它了

方法1:利用动态申请内存,一定是可执行属性

复制代码
typedef void (_stdcall *CODE)();


VOID Sub_1()
{
    PVOID p = NULL;
    p = VirtualAlloc(NULL, sizeof(ShellCode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (p == NULL) { return; } memcpy(p, ShellCode, sizeof(ShellCode)); CODE code = (CODE)p; code(); }
复制代码

方法2,:强制类型转换成函数指针

VOID Sub_2()
{
    ((void(WINAPI*)(void))&ShellCode)();
}

虽然看上去有点复杂,但是拆开分析一下还是很简单的,首先取了ShellCode的地址,将它强制类型转换成函数指针,第一个void表示函数返回值,第二个void可以不要,它是说该函数没有参数,最后在后面加上小括号,注意WINAPI的调用约定一定不能少,我用的VS2015编译器,写的控制台程序的默认调用约定是_cdecl。

 

方法3:嵌入式汇编呼叫ShellCode

复制代码

#pragma comment(linker, "/section:.data,RWE")
VOID Sub_3() { __asm { mov eax, offset ShellCode jmp eax } }
复制代码

这种方法写法也比较灵活,其中第一句 mov eax, offset ShellCode 可以用 lea eax, ShellCode 代替,因为它们是等价的

第二句的 jmp 也可以用 call 代替。所以就是四种组合了。

最上面的一句 #pragma comment(linker, "/section:.data,RWE") 是很重要的,我曾经因为没有它,而导致多次错误,却一直在ShellCode上找原因。

它也是说将这段代码放入可执行区域。

 

方法4:伪指令

复制代码
#pragma comment(linker, "/section:.data,RWE"
VOID Sub_4()
{
    __asm
    {
        
        mov eax, offset ShellCode
       ;_emit 伪指令在当前文本段落的当前位置定义一个字节。 _emit 伪命令类似于 MASM 的 DB 指令。
        _emit 0xFF  
        _emit 0xE0

    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Blood_Seeker

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值