richard_ljd 发表于 2024-9-16 15:26

[已经解决]向执行文件exe写入shellcode的疑问(E8计算)

本帖最后由 richard_ljd 于 2024-9-17 08:25 编辑

问题解决了
我命名的变量名codebegin把自己迷惑住了,那个只是在FIlebuffer文件状态下的地址,要写入内存状态的地址才行,

因为我自己命名时codebegin,我以为已经算的是Imagebuffer的地址,结果少了一个Imagebase,所以一直有错,函数改了一下就好了

    //复制CALL,且计算 MESSAGEBOX_WZ - (CALL + 5)实际参数,计算下一句地址需要 - PointerToRawData + VirtualAddress得到内存状态实际地址
    int call_s = MESSAGEBOXW_WZ - (pOptionHeader->ImageBase + codebegin + 0xD);            //<------------这里
    BYTE c_wz;
    mitol(call_s, c_wz);

    memcpy(Shellcode + 0x9, c_wz, 4);



==================================================================================

最近在看教程,老师让用代码的方式自动在程序中写入ShellCode,且能够运行

在手动写入了以后,我也开始了代码写入,先简单来说一下过程

首先程序读入exe文件到FileBuffer,然后进行PE分析,分析完毕以后将FileBuffer转变成ImageBuffer,

随后我将我的ShellCode在这个ImageBuffer中寻找有空闲区域的节(防止自己写入的代码被覆盖),找到以后VirtualAddress + VirtualSize可以到节尾,



BYTE Shellcode[] =
{
    0x6A,00,0x6A,00,0x6A,00,0x6A,00,
    0xE8,00,00,00,00,
    0xE9,00,00,00,00
};
int PeHeader::AddShellcode(int Number)
{

    int fsize = 0;

//遍历节,看是否有可以写入的节区
    for (Number - 1; Number < pPEHeader->NumberOfSections; Number++)
    {
      fsize = (pSectionHeader + Number)->SizeOfRawData - (pSectionHeader + Number)->Misc.VirtualSize;

      if (fsize > Shellcode_length)
            break;

      if (Number == pPEHeader->NumberOfSections - 1)
            return 0;
    }


    int codebegin = (pSectionHeader + Number)->VirtualAddress + (pSectionHeader + Number)->Misc.VirtualSize;

    //复制CALL,且计算 MESSAGEBOX_WZ - (CALL + 5)实际参数,计算下一句地址需要 - PointerToRawData + VirtualAddress得到内存状态实际地址
    int call_s = MESSAGEBOXW_WZ - (codebegin + 0xE);
    BYTE c_wz;
    mitol(call_s, c_wz);

    memcpy(Shellcode + 0x9, c_wz, 4);

    //复制JMP,且计算 OEP - (JMP + 5)实际参数
    int jmp_s = pOptionHeader->AddressOfEntryPoint - (codebegin + 18);
    BYTE j_wz;
    mitol(jmp_s, j_wz);

    memcpy(Shellcode + 0xE, j_wz, 4);

    //修改OEP,指向添加代码的位置
    BYTE OEP;
    mitol((pSectionHeader + Number)->Misc.VirtualSize + (pSectionHeader + Number)->VirtualAddress, OEP);
    memcpy((void*)((DWORD)pNewBuffer + ((DWORD)pOptionHeader - (DWORD)pDosHeader) + 0x10), OEP, 4);

    //将计算好的ShellCode写入pNewBuffer
    memcpy((void*)((DWORD)pNewBuffer + codebegin), Shellcode, 18);

    return pOptionHeader->AddressOfEntryPoint;
}


然后如上面这个代码段,添加CALL和JMP的地址,修改OEP

代码方面计算基本没有问题(实际有问题,也是这个帖子发出来的原因,不过先继续)

程序跑起来以后,直接运行引发未知错误直接结束,所以我挂上dbg



这个报错提示告诉我:1.指针为空2.数组越界   3.堆栈溢出    4.内存损坏   5.硬件问题   6.无权限

这六个可能中前5个不好评价,第六个的话也不清楚怎么办(但是应该好歹调试器里面会显示到正确的位置吧)

于是我打算进程序里面看看,跟着jmp走了一会跳进了程序


这边用的是FF15,我尝试改成E8

发现也是可以的,但是回到我的Shellcode就直接炸了,不清楚为什么

下面是完整的代码,能Filebuffer和Imagebuffer相互转换,然后就没什么了()

微云网盘:https://share.weiyun.com/lVcTTb6Q
百度网盘:https://pan.baidu.com/s/1Y4XIVcBEDwEpQE2O9SES_A                  提取码:1234

richard_ljd 发表于 2024-9-16 15:43

Vvvvvoid 发表于 2024-9-16 15:32
shell code 写成这样试试
pushad
push 0

你说的是这种么?裸函数,然后内联汇编,随后直接复制出来就是完整代码

int __declspec(naked) shellcode()
{
    _asm {
      push 0;
      push 0;
      push 0;
      push 0;
      CALL MessageBoxA;
    }
}

int (*p)() = shellcode;

这个虽然是一种办法,但是麻烦的还是E8跳转时Messagebox经过计算的位置才行,如果放在代码内部,这个计算是根据这个函数位置进行计算,我写到其他地方也失效了

如果我理解错了希望能够指出来

海水很咸 发表于 2024-9-18 18:22

richard_ljd 发表于 2024-9-17 08:03
是很早,早到没法查(),所以这个阶段我想去调用函数都是用dbg进去先查好的用,就像代码里的宏MESSAGEBO ...

仔细看了下 你的代码, 出错的地方 在这里    int call_s = MESSAGEBOXW_WZ - (codebegin + 0xE);

        //运行出错 是因为 实际运行 call_s-= (模块起始地址 +1);

    BYTE c_wz;
    mitol(call_s, c_wz); 你给这个变量加个重定位 让他在运行的时候自己修正。试试

Vvvvvoid 发表于 2024-9-16 15:32


shell code 写成这样试试
pushad
push 0
push 0
push 0
push 0
call MessageBoxA
popad
ret

woflant 发表于 2024-9-16 16:45

richard_ljd 发表于 2024-9-16 15:43
你说的是这种么?裸函数,然后内联汇编,随后直接复制出来就是完整代码

int __declspec(naked) shellc ...

楼上的意思是shellcode增加pushad、popad,保存寄存器环境,避免返回到原来汇编处污染寄存器数据

richard_ljd 发表于 2024-9-16 18:06

woflant 发表于 2024-9-16 16:45
楼上的意思是shellcode增加pushad、popad,保存寄存器环境,避免返回到原来汇编处污染寄存器数据

az,这个东西是把原本oep换成自己的代码,代码跑完就转到原本的oep,不会再回来了,如果硬要说的话得
pushad
push 0
push 0
push 0
push 0
call messagebox
popad
jmp 原oep
代码不会运行回来
messagebox我没记错的话影响的返回值在eax,不会造成什么太大影响,未来写更多东西的时候我注意一下

海水很咸 发表于 2024-9-16 19:12

如果 你在OEP之前运行 会不会 时机太早 ,要自己获取下MessageBoxA 的地址 才行。

zishen 发表于 2024-9-16 22:52

这样确实有隐患问题,想如果是APIHOOK,微软有热补丁前五个字节用来修改,你要是在OEP前执行代码,原本的寄存器的值,还有栈帧被修改,跳转到OEP的时候没有被还原,是这个问题吗?

richard_ljd 发表于 2024-9-17 08:03

海水很咸 发表于 2024-9-16 19:12
如果 你在OEP之前运行 会不会 时机太早 ,要自己获取下MessageBoxA 的地址 才行。

是很早,早到没法查(),所以这个阶段我想去调用函数都是用dbg进去先查好的用,就像代码里的宏MESSAGEBOX_WZ就是MesssageboxW函数的地址,不过计算是一方面,我自己进到我写入ShellCode的程序,手算填进去也无法找到,这就是我问题的来源()

richard_ljd 发表于 2024-9-19 07:30

海水很咸 发表于 2024-9-18 18:22
仔细看了下 你的代码, 出错的地方 在这里    int call_s = MESSAGEBOXW_WZ - (co ...

这点我当时调试的时候发现了,已经改正,不过主要问题不是在于这里,问题在于codebegin这个变量本来应该实在Imagebuffer中的地址,但是我没有加入Imagebase,所以一下子地址差了40000,所以出现报错(都跑程序外了,这还不报错),加上以后就好了,你可以看一下我修改了最开始的帖子。
页: [1] 2
查看完整版本: [已经解决]向执行文件exe写入shellcode的疑问(E8计算)