原创首发,不调用CreateProcess,启动Win32程序
本帖最后由 aswcy815174418 于 2021-11-27 20:48 编辑**大体思路:拉伸→修复导入表→修复重定位表→创建线程(定义winmain函数指针,并传入参数调用),效果图在最底下
**
**写这个源码的缘由: 前几天面试了一家安全公司,面试官问我,内核重载后,全局变量怎么处理,我想了想
不是修复重定位表就可以了嘛?后来仔细想了想,重定位只是修复了全局变量的地址,并没有初始化内核重载后,
全局变量所存的值,后来研究了下,什么时候全局变量会初始化
一丶编译前就赋了初始值,没有的话默认就赋值为0
二丶从main函数开始初始化(并没有准确的说,就是在main函数初始化,也可能是main函数调了其它函数进行初始化的)
内核文件,经过研究发现,全局变量用的是第二种进行初始化,如果把内核文件,拉伸,重定位,修复导入表
如果知道内核main函数参数,用文中的方法,可能会解决掉全局变量的处理(意味着,可以不用老内核的数据,直接用新内核数据)
**
**测试用到的文件: [点我下载](https://www.lanzouw.com/iXUaywyrqze
)**
```
// LoadProcess.cpp : Defines the entry point for the console application.
//
#include "windows.h"
#include "stdio.h"
//隐藏控制台
//#pragma comment(linker,"/subsystem:\"windows\"/entry:\"mainCRTStartup\"" )
//重定位
BOOL modify_base_table(TCHAR* imagebuffer, DWORD new_imagebasse);
DWORD ThreadProc(PVOID Parameter) {
typedef BOOL(APIENTRY *CallMain)(HMODULE hModule,
DWORDul_reason_for_call,
LPVOID lpReserved
);
PIMAGE_DOS_HEADER h_dos_header = (PIMAGE_DOS_HEADER)Parameter;//dos头
PIMAGE_NT_HEADERS hNt = (PIMAGE_NT_HEADERS)((DWORD)Parameter + h_dos_header->e_lfanew);//nt头
DWORD OEP = hNt->OptionalHeader.AddressOfEntryPoint + (DWORD)Parameter;
CallMain p = OEP;
p((DWORD)Parameter, 1, 0);
return 0;
}
int main(int argc, char* argv[]) {
DWORD size_file = 0;//文件大小
char* filebuffer = NULL;//filebuffer
char* imagebuffer = NULL;//imagebase
DWORD sizeofimage = NULL;//文件的sizeofimage
DWORD number_section = 0;//节的数量
DWORD size_all_headers = 0;//所有头的大小
//用fopen打开一个进程
FILE* h_file = fopen("C:\\win32.exe", "rb+");
DWORD DD = GetLastError();
if (NULL == h_file) {
printf("用fopen打开文件失败,请检查文件地址是否错误\n");
return -1;
}
//得到其大小
fseek(h_file, 0, SEEK_END);
size_file = ftell(h_file);
fseek(h_file, 0, SEEK_SET);
//为其申请内存
filebuffer = (char*)malloc(size_file);
//初始化内存
memset(filebuffer, 0, size_file);
if (NULL == filebuffer) {
printf("申请filebuffer失败\n");
return -1;
}
//文件写入内存
fread(filebuffer, 1, size_file, h_file);
if (IMAGE_DOS_SIGNATURE != *(short*)filebuffer) {
printf("该文件不是PE文件\n");
return -1;
}
//得到其sizeofimage
PIMAGE_DOS_HEADER hDos = (PIMAGE_DOS_HEADER)filebuffer;//dos头
PIMAGE_NT_HEADERS hNt = (PIMAGE_NT_HEADERS)(filebuffer + hDos->e_lfanew);//nt头
if (IMAGE_NT_SIGNATURE != hNt->Signature) {
printf("该文件不是PE文件\n");
return -1;
}
sizeofimage = hNt->OptionalHeader.SizeOfImage;
//拉伸
//申请内存
imagebuffer = (char*)malloc(sizeofimage);
if (NULL == imagebuffer) {
printf("申请imagebuffer失败\n");
return -1;
}
//初始化内存
memset(imagebuffer, 0, sizeofimage);
//得到节表
PIMAGE_SECTION_HEADER SectionArr = (PIMAGE_SECTION_HEADER)((DWORD)hNt + 24 + hNt->FileHeader.SizeOfOptionalHeader);
//得到节的数量
number_section = hNt->FileHeader.NumberOfSections;
//得到所有头的大小
size_all_headers = hNt->OptionalHeader.SizeOfHeaders;
//复制头
memcpy(imagebuffer, filebuffer, size_all_headers);
//复制节区
while (number_section--) {
DWORD VirtualAddress = 0;
DWORD PointerToRawData = 0;
DWORD SizeOfRawData = 0;
//得到VirtualAddress
VirtualAddress = SectionArr->VirtualAddress;
//得到PointerToRawData
PointerToRawData = SectionArr->PointerToRawData;
//得到SizeOfRawData
SizeOfRawData = SectionArr->SizeOfRawData;
memcpy(imagebuffer + VirtualAddress, filebuffer + PointerToRawData, SizeOfRawData);
SectionArr++;
}
//修复iat表
//得到导入表
PIMAGE_IMPORT_DESCRIPTOR ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)(imagebuffer + hNt->OptionalHeader.DataDirectory.VirtualAddress);
while (0 != ImportTable->FirstThunk) {
//得到dll名字
char* dll_name = imagebuffer + ImportTable->Name;
//得到iat表
int* IatTable = (int*)(imagebuffer + ImportTable->FirstThunk);
while (*IatTable) {
//判断最高位是不是1
if ((*IatTable) & 0x80000000) {
*IatTable = (DWORD)GetProcAddress(LoadLibrary(dll_name), (char*)((*IatTable) & 0x7FFFFFFF));
IatTable++;
} else {
//得到By_Name结构体
PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)(imagebuffer + *IatTable);
char* function_name = (char*)by_name->Name;
*IatTable = (DWORD)GetProcAddress(LoadLibrary(dll_name), function_name);
IatTable++;
}
}
ImportTable++;
}
//修复重定位表
if (FALSE == modify_base_table((TCHAR*)imagebuffer, (DWORD)imagebuffer)) {
printf("重定位失败\n");
return -1;
}
//老属性
DWORD old;
//修改为可执行,可读可写
VirtualProtect(imagebuffer, hNt->OptionalHeader.SizeOfImage, PAGE_EXECUTE_READWRITE, &old);
//从OEP开始跑
HANDLE hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ThreadProc, imagebuffer, 0, 0);
WaitForSingleObject(hThread, -1);
fclose(h_file);
free(filebuffer);
free(imagebuffer);
return 0;
}
BOOL modify_base_table(TCHAR* imagebuffer, DWORD new_imagebasse) {
DWORD imagebase = 0;
//判断有没有重定位表
//得到NT头
PIMAGE_DOS_HEADER exe_f_dos_header = (PIMAGE_DOS_HEADER)imagebuffer;
PIMAGE_NT_HEADERS exe_f_nt_header = (PIMAGE_NT_HEADERS)((DWORD)imagebuffer + (DWORD)exe_f_dos_header->e_lfanew);
//得到imagebase
imagebase = exe_f_nt_header->OptionalHeader.ImageBase;
//得到重定位表
PIMAGE_BASE_RELOCATION exe_f_base_relocation = (PIMAGE_BASE_RELOCATION)(imagebuffer + exe_f_nt_header->OptionalHeader.DataDirectory.VirtualAddress);
//判断
if (0 == exe_f_base_relocation->VirtualAddress && 0 == exe_f_base_relocation->SizeOfBlock) {
return FALSE;
}
//修复
while (0 != exe_f_base_relocation->VirtualAddress && 0 != exe_f_base_relocation->SizeOfBlock) {
int* virtual_add = NULL;
short value = 0;
//得到要修复的数量
DWORD number_of_modify = (exe_f_base_relocation->SizeOfBlock - 8) / 2;
//得到要修复的位置
short* adderss_of_modify = (short*)((DWORD)exe_f_base_relocation + 8);
//开始
while (number_of_modify--) {
value = *adderss_of_modify;
//判断最高位是不是3
if (value >> 12 == 3) {
//去掉前面的属性
value = value & 0x0FFF;
virtual_add = (int*)(imagebuffer + exe_f_base_relocation->VirtualAddress + value);
*virtual_add = *virtual_add - imagebase + new_imagebasse;
}
adderss_of_modify++;
}
//得到下一个块的地址
exe_f_base_relocation = (PIMAGE_BASE_RELOCATION)((DWORD)exe_f_base_relocation + exe_f_base_relocation->SizeOfBlock);
}
//更改imagebase
exe_f_nt_header->OptionalHeader.ImageBase = new_imagebasse;
return TRUE;
}
``` 想起来在哪里看到过类似的了,这个操作其他进程的,原理应该差不多
https://blog.csdn.net/xfgryujk/article/details/81360292 牛逼,长知识了 学 习 了 {:1_893:} 这不是PE的知识么? CC000731 发表于 2021-11-27 22:28
这不是PE的知识么?
就是PE知识 易语言EXE没有重定位怎么办? 涨知识了,不错。 感谢,请问能否搞成支持X64的??? 今天又学习了一个新知识!! 支持原创
页:
[1]
2