我写了个加壳程序,写完之后可以存盘.但是shellcode写入的地方应该是第一个节在内存中空闲的位置,但是我用PEtool打开发现却是在第二个节里。而且用Winhex打开的时候shellcode在文件的地址是C00,我将其根据FOA转RVA之后得到的数值跟程序原本计算的OEP地址也不一样。求大佬帮忙解决。小白万分感谢
VOID ShellCode()
{
//可以通过硬编码,将要执行的函数全抠出来扔到这个Shellcode数组里
BYTE Shellcode[] =
{
0X6A,0X00,0X6A,0X00,0X6A,0X00,0X6A,0X00,
0XE8,0X00,0X00,0X00,0X00,
0XE9,0X00,0X00,0X00,0X00
};
DWORD ShellcodeSize = sizeof(Shellcode);
cout << "ShellcodeSize大小:" << hex<<ShellcodeSize<< endl;;
LPVOID LS= FileBufferToImageBuffer(); //拉伸后的空间返回的地址
PIMAGE_DOS_HEADER LSDOS = (PIMAGE_DOS_HEADER)LS;
PIMAGE_NT_HEADERS LSNT = (PIMAGE_NT_HEADERS)((char*)LS + LSDOS->e_lfanew);
PIMAGE_FILE_HEADER LSFILE = (PIMAGE_FILE_HEADER)((char*)LS + LSDOS->e_lfanew + 4);
PIMAGE_OPTIONAL_HEADER64 LSOP64 = (PIMAGE_OPTIONAL_HEADER64)((char*)LS + LSDOS->e_lfanew + 4+IMAGE_SIZEOF_FILE_HEADER);
PIMAGE_SECTION_HEADER LSSEC = (PIMAGE_SECTION_HEADER)((char*)LS + LSDOS->e_lfanew + 4 + IMAGE_SIZEOF_FILE_HEADER + LSFILE->SizeOfOptionalHeader);
for (int i = 0; i < LSFILE->NumberOfSections; i++)
{
if (ShellcodeSize < LSSEC[i].SizeOfRawData - LSSEC[i].Misc.VirtualSize)
{
printf("第%x个节%s可以注入\n", i + 1, LSSEC[i].Name); //判断哪个节可以注入
}
else
{
printf("第%x个节%s不可以注入\n", i + 1, LSSEC[i].Name); //判断哪个节不可以注入
}
}
LPVOID PointMessage = NULL;
PointMessage = &MessageBoxA;
printf("MessageBoxA在内存中的地址是%lx\n", PointMessage);
//printf("写死的MessageBoxAddr的地址是%lx\n", MessageBoxAddr);
for (int i = 0; i < LSFILE->NumberOfSections; i++)
{
if (ShellcodeSize < LSSEC[i].SizeOfRawData - LSSEC[i].Misc.VirtualSize) //判断注入空间大小是否满足 shellcode代码长度<文件对齐后大小-文件对齐前的大小
{
printf("从第%x个节%s注入\n", i + 1, LSSEC[i].Name);
//CodeBegin
char* CodeBegin = (char*)((DWORD)LS + LSSEC[i].VirtualAddress + LSSEC[i].Misc.VirtualSize); //代码注入开始的地方,Imagebuff 既节的内存偏移+节的尺寸
printf("代码开始注入的内存地址是%lx\n", CodeBegin);
memcpy(CodeBegin, Shellcode, ShellcodeSize); //把shellcode的代码从数组里拷贝到拉伸的内存中
char* E8 = ((char*)CodeBegin + 0X9);
char* E8next = ((char*)CodeBegin + 0XD);
//X=MessageBoxA的地址-E8下一条在内存中的地址—>MessageBoxA-(E8当前地址-buff=得到的偏移+实际中的内存)
DWORD X = ((DWORD)PointMessage - ((DWORD)E8next - (DWORD)LS + (DWORD)LSOP64->ImageBase)); //得到E8下一条指令真正在内存中运行的地址
printf("E8里X的数值=%lx\n", X);
//改E8 将E8改成PDWORD的地址然后取值,取到的就是DWORD数据类型,然后将X的值写入
*(PDWORD)(E8) = X;
printf("E8的数值是%lx,X的数值是%lx\n", *(PDWORD)(E8), X);
/*这个Y = OEP - E9下一条指令的地址并不是正确的
// 错误的是:Y=OEP-E9下一条指令在内存中的地址
// 正确的是:Y=内存目标地址-E9下一条指令在内存中的地址
//这里有个非常重要的知识点 Y=目标地址-E9下一条在内存中的地址,所以我们不能单单拿OEP去减掉他的数值,而是将 ImageBase+OEP
//因为 ImageBase+OEP才是我们要跳转的目标地址,这个地址是在内存中的,所以我们要加上内存基址 ImageBase
//而E9下一条在内存中的地址是(DWORD)(((DWORD)E9next - (DWORD)LS) + LSOP64->ImageBase)) 是将E9下一条指令的地址-我们申请空间
//的基本地址然后加上真正的内存基址ImageBase,这样的数值才是E9下一条在内存中的地址 2022/2/6
*/
char* E9 = ((char*)CodeBegin + 0XE); //E9地址
char* E9next = ((char*)CodeBegin + ShellcodeSize);//E9下一条指令的地址
DWORD Y = ((DWORD)(LSOP64->ImageBase+LSOP64->AddressOfEntryPoint) - (DWORD)
(((DWORD)E9next - (DWORD)LS) + LSOP64->ImageBase));
printf("E9里X的数值=%lx\n", Y);
//改E9 将E9改成PWORD的地址然后取值,取到的就是DWORD数据类型,然后将Y的值写入
*(PDWORD)(E9) = Y;
printf("E9的数值是%lx,Y的数值是%lx\n", *(PDWORD)(E9), Y);
//改OEP
printf("修改前的OEP=%lx\n", LSOP64->AddressOfEntryPoint);
LSOP64->AddressOfEntryPoint = (DWORD)CodeBegin - (DWORD)LS;
printf("修改后的OEP=%lx\n", LSOP64->AddressOfEntryPoint);
break;
}
else
{
printf("Shellcode注入的空间不够\n");
break;
}
}
//return LS;
cout << "shellcode函数执行结束" << endl;
LPVOID shellcodebuffer = ImageBufferToNewBuffer(LS); //把注入好shellcode后的ImageBuffer压缩成Newbuffer
FileSave(shellcodebuffer);
}
求大神解答 困扰了我好多天。。。
万分感谢!
/(ㄒoㄒ)/~~
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2022-2-6 06:39
被白嫖怪编辑
,原因: 添加附件