首页
社区
课程
招聘
[旧帖] 求助怎么改一个EXE文件的镜像基址,改了后要能够运行! 0.00雪花
发表于: 2016-6-4 20:17 10510

[旧帖] 求助怎么改一个EXE文件的镜像基址,改了后要能够运行! 0.00雪花

2016-6-4 20:17
10510
我要改EXE文件的镜像基址,我直接修改,程序不能运行。请教怎么改了后能够运行,是不是只有编译的时候才能改这个了。编译出来就改不了了?有什么工具可以直接改的吗


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (9)
雪    币: 4522
活跃值: (5154)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
2
要有重定位节才能改的,改了基址还要修复所有引用到的重定位信息才行。
2016-6-4 20:32
0
雪    币: 4730
活跃值: (3239)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
那意思是修改一个镜像基址很麻烦是吗,有教程吗
2016-6-4 20:35
0
雪    币: 4522
活跃值: (5154)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
4
不晓得哪里有教程 你了解PE加载器的工作原理了,就知道怎么改了。
即PE文件如何加载到内存并启动起来。
2016-6-4 21:06
0
雪    币: 608
活跃值: (648)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
首先载入PE,判断一下这个PE是否有重定位表。如果有,遍历重定位表,找到每一个需要重定位的RVA,给他改到你想要的基址上,最后更新PE头里的ImageBase为你想要的地址。 不过如果有重定位表的话,在有ASLR的系统上面不一定会加载到你想要的那个地址上
2016-6-5 00:00
0
雪    币: 19
活跃值: (1086)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
嘻嘻,EXE的话,你编译的时候指定生成重定位表,随便你怎么改
2016-6-5 00:46
0
雪    币: 878
活跃值: (496)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
编译期指定基址就好, 常规EXE一般不带重定位表, 目测楼主想内存加载EXE
2016-6-5 10:03
0
雪    币: 4730
活跃值: (3239)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
是的,你怎么知道,我想内存加载一个C++ 的EXE文件。要改映像基址才行。
2016-6-5 13:30
0
雪    币: 1114
活跃值: (2094)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
9
转自http://zhan.renren.com/zeroevent?gid=3602888498033743271&checked=true 自动对齐节
内存中运行EXE程序

在内存中运行可执行程序,好处是可以给程序加壳,加密源程序,静态反汇编无法获得PE输入节,但是因为运行后仍然是独立的进程,所以没办法防止远程线程注入,挂接API钩子。

Windows的PE加载器在启动程序的时候,会将磁盘上的文件加载到内存,然后做很多操作,如函数导入表重定位,变量预处理之类的。这位仁兄等于是自己写了一个PE加载器。直接将内存中的程序启动。记得以前的“红色代码”病毒也有相同的特性。

直接启动内存中的程序相当于加了一个壳,可以把程序加密保存,运行时解密到内存,然后启动,不过对于增加破解难度还要稍微复杂点。否则人家把内存中的进程DUMP出来然后修复导入表就被拖出来了。





#include "stdafx.h"


typedef IMAGE_SECTION_HEADER (*PIMAGE_SECTION_HEADERS)[1];

// 计算对齐后的大小
unsigned long GetAlignedSize(unsigned long Origin, unsigned long Alignment)
{
return (Origin + Alignment - 1) / Alignment * Alignment;
}

// 计算加载pe并对齐需要占用多少内存
// 未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0
unsigned long CalcTotalImageSize(PIMAGE_DOS_HEADER MzH
, unsigned long FileLen
, PIMAGE_NT_HEADERS peH
, PIMAGE_SECTION_HEADERS peSecH)
{
unsigned long res;
// 计算pe头的大小
res = GetAlignedSize( peH->OptionalHeader.SizeOfHeaders
, peH->OptionalHeader.SectionAlignment
);

// 计算所有节的大小
for( int i = 0; i < peH->FileHeader.NumberOfSections; ++i)
{
// 超出文件范围
if(peSecH->PointerToRawData + peSecH->SizeOfRawData > FileLen)
return 0;
else if(peSecH->VirtualAddress)//计算对齐后某节的大小
{
if(peSecH->Misc.VirtualSize)
{
res = GetAlignedSize( peSecH->VirtualAddress + peSecH->Misc.VirtualSize
, peH->OptionalHeader.SectionAlignment
);
}
else
{
res = GetAlignedSize( peSecH->VirtualAddress + peSecH->SizeOfRawData
, peH->OptionalHeader.SectionAlignment
);
}
}
else if( peSecH->Misc.VirtualSize < peSecH->SizeOfRawData )
{
res += GetAlignedSize( peSecH->SizeOfRawData
, peH->OptionalHeader.SectionAlignment
);
}
else
{
res += GetAlignedSize( peSecH->Misc.VirtualSize
, peH->OptionalHeader.SectionAlignment
);
}// if_else
}// for

return res;
}




// 加载pe到内存并对齐所有节
BOOL AlignPEToMem( void *Buf
, long Len
, PIMAGE_NT_HEADERS &peH
, PIMAGE_SECTION_HEADERS &peSecH
, void *&Mem
, unsigned long &ImageSize)
{
PIMAGE_DOS_HEADER SrcMz;// DOS头
PIMAGE_NT_HEADERS SrcPeH;// PE头
PIMAGE_SECTION_HEADERS SrcPeSecH;// 节表

SrcMz = (PIMAGE_DOS_HEADER)Buf;

if( Len < sizeof(IMAGE_DOS_HEADER) )
return FALSE;

if( SrcMz->e_magic != IMAGE_DOS_SIGNATURE )
return FALSE;

if( Len < SrcMz->e_lfanew + (long)sizeof(IMAGE_NT_HEADERS) )
return FALSE;

SrcPeH = (PIMAGE_NT_HEADERS)((int)SrcMz + SrcMz->e_lfanew);
if( SrcPeH->Signature != IMAGE_NT_SIGNATURE )
return FALSE;

if( (SrcPeH->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
(SrcPeH->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE == 0) ||
(SrcPeH->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER)) )
{
return FALSE;
}


SrcPeSecH = (PIMAGE_SECTION_HEADERS)((int)SrcPeH + sizeof(IMAGE_NT_HEADERS));
ImageSize = CalcTotalImageSize( SrcMz, Len, SrcPeH, SrcPeSecH);

if( ImageSize == 0 )
return FALSE;

Mem = VirtualAlloc( NULL, ImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // 分配内存
if( Mem != NULL )
{
// 计算需要复制的PE头字节数
unsigned long l = SrcPeH->OptionalHeader.SizeOfHeaders;
for( int i = 0; i < SrcPeH->FileHeader.NumberOfSections; ++i)
{
if( (SrcPeSecH->PointerToRawData) &&
(SrcPeSecH->PointerToRawData < l) )
{
l = SrcPeSecH->PointerToRawData;
}
}
memmove( Mem, SrcMz, l);
peH = (PIMAGE_NT_HEADERS)((int)Mem + ((PIMAGE_DOS_HEADER)Mem)->e_lfanew);
peSecH = (PIMAGE_SECTION_HEADERS)((int)peH + sizeof(IMAGE_NT_HEADERS));

void *Pt = (void *)((unsigned long)Mem
+ GetAlignedSize( peH->OptionalHeader.SizeOfHeaders
, peH->OptionalHeader.SectionAlignment)
);

for( i = 0; i < peH->FileHeader.NumberOfSections; ++i)
{
// 定位该节在内存中的位置
if(peSecH->VirtualAddress)
Pt = (void *)((unsigned long)Mem + peSecH->VirtualAddress);

if(peSecH->SizeOfRawData)
{
// 复制数据到内存
memmove(Pt, (const void *)((unsigned long)(SrcMz) + peSecH->PointerToRawData), peSecH->SizeOfRawData);
if(peSecH->Misc.VirtualSize < peSecH->SizeOfRawData)
Pt = (void *)((unsigned long)Pt + GetAlignedSize(peSecH->SizeOfRawData, peH->OptionalHeader.SectionAlignment));
else // pt 定位到下一节开始位置
Pt = (void *)((unsigned long)Pt + GetAlignedSize(peSecH->Misc.VirtualSize, peH->OptionalHeader.SectionAlignment));
}
else
{
Pt = (void *)((unsigned long)Pt + GetAlignedSize(peSecH->Misc.VirtualSize, peH->OptionalHeader.SectionAlignment));
}
}
}
return TRUE;
}



typedef void *(__stdcall *pfVirtualAllocEx)(unsigned long, void *, unsigned long, unsigned long, unsigned long);
pfVirtualAllocEx MyVirtualAllocEx = NULL;

BOOL IsNT()
{
return MyVirtualAllocEx!=NULL;
}

// 生成外壳程序命令行
char *PrepareShellExe(char *CmdParam, unsigned long BaseAddr, unsigned long ImageSize)
{
if(IsNT())
{
char *Buf = new char[256];
memset(Buf, 0, 256);
GetModuleFileName(0, Buf, 256);
strcat(Buf, CmdParam);
return Buf; // 请记得释放内存;-)
}
else
{
// Win98下的处理请参考原文;-)
// http://community.csdn.net/Expert/topic/4416/4416252.xml?temp=8.709133E-03
return NULL;
}
}

// 是否包含可重定向列表
BOOL HasRelocationTable(PIMAGE_NT_HEADERS peH)
{
return (peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
&& (peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
}




#pragma pack(push, 1)
typedef struct{
unsigned long VirtualAddress;
unsigned long SizeOfBlock;
} *PImageBaseRelocation;
#pragma pack(pop)

// 重定向PE用到的地址
void DoRelocation(PIMAGE_NT_HEADERS peH, void *OldBase, void *NewBase)
{
unsigned long Delta = (unsigned long)NewBase - peH->OptionalHeader.ImageBase;
PImageBaseRelocation p = (PImageBaseRelocation)((unsigned long)OldBase
+ peH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
while(p->VirtualAddress + p->SizeOfBlock)
{
unsigned short *pw = (unsigned short *)((int)p + sizeof(*p));
for(unsigned int i=1; i <= (p->SizeOfBlock - sizeof(*p)) / 2; ++i)
{
if((*pw) & 0xF000 == 0x3000){
unsigned long *t = (unsigned long *)((unsigned long)(OldBase) + p->VirtualAddress + ((*pw) & 0x0FFF));
*t += Delta;
}
++pw;
}
p = (PImageBaseRelocation)pw;
}
}

// 卸载原外壳占用内存
BOOL UnloadShell(HANDLE ProcHnd, unsigned long BaseAddr)
{
typedef unsigned long (__stdcall *pfZwUnmapViewOfSection)(unsigned long, unsigned long);
pfZwUnmapViewOfSection ZwUnmapViewOfSection = NULL;
BOOL res = FALSE;
HMODULE m = LoadLibrary("ntdll.dll");
if(m){
ZwUnmapViewOfSection = (pfZwUnmapViewOfSection)GetProcAddress(m, "ZwUnmapViewOfSection");
if(ZwUnmapViewOfSection)
res = (ZwUnmapViewOfSection((unsigned long)ProcHnd, BaseAddr) == 0);
FreeLibrary(m);
}
return res;
}

// 创建外壳进程并获取其基址、大小和当前运行状态
BOOL CreateChild(char *Cmd, CONTEXT &Ctx, HANDLE &ProcHnd, HANDLE &ThrdHnd,
unsigned long &ProcId, unsigned long &BaseAddr, unsigned long &ImageSize)
{
STARTUPINFOA si;
PROCESS_INFORMATION pi;
unsigned long old;
MEMORY_BASIC_INFORMATION MemInfo;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);

BOOL res = CreateProcess(NULL, Cmd, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); // 以挂起方式运行进程;
if(res){
ProcHnd = pi.hProcess;
ThrdHnd = pi.hThread;
ProcId = pi.dwProcessId;
// 获取外壳进程运行状态,[ctx.Ebx+8]内存处存的是外壳进程的加载基址,ctx.Eax存放有外壳进程的入口地址
Ctx.ContextFlags = CONTEXT_FULL;
GetThreadContext(ThrdHnd, &Ctx);
ReadProcessMemory(ProcHnd, (void *)(Ctx.Ebx+8), &BaseAddr, sizeof(unsigned long), &old); // 读取加载基址
void *p = (void *)BaseAddr;
// 计算外壳进程占有的内存
while(VirtualQueryEx(ProcHnd, p, &MemInfo, sizeof(MemInfo)))
{
if(MemInfo.State = MEM_FREE) break;
p = (void *)((unsigned long)p + MemInfo.RegionSize);
}
ImageSize = (unsigned long)p - (unsigned long)BaseAddr;
}
return res;
}

// 创建外壳进程并用目标进程替换它然后执行
HANDLE AttachPE(char *CmdParam, PIMAGE_NT_HEADERS peH, PIMAGE_SECTION_HEADERS peSecH,
void *Ptr, unsigned long ImageSize, unsigned long &ProcId)
{
HANDLE res = INVALID_HANDLE_VALUE;
CONTEXT Ctx;
HANDLE Thrd;
unsigned long Addr, Size;
char *s = PrepareShellExe(CmdParam, peH->OptionalHeader.ImageBase, ImageSize);
if(s==NULL) return res;
if(CreateChild(s, Ctx, res, Thrd, ProcId, Addr, Size)){
void *p = NULL;
unsigned long old;
if((peH->OptionalHeader.ImageBase == Addr) && (Size >= ImageSize)){// 外壳进程可以容纳目标进程并且加载地址一致
p = (void *)Addr;
VirtualProtectEx(res, p, Size, PAGE_EXECUTE_READWRITE, &old);
}
else if(IsNT()){
if(UnloadShell(res, Addr)){// 卸载外壳进程占有内存
p = MyVirtualAllocEx((unsigned long)res, (void *)peH->OptionalHeader.ImageBase, ImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
}
if((p == NULL) && HasRelocationTable(peH)){// 分配内存失败并且目标进程支持重定向
p = MyVirtualAllocEx((unsigned long)res, NULL, ImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(p) DoRelocation(peH, Ptr, p); // 重定向
}
}
if(p){
WriteProcessMemory(res, (void *)(Ctx.Ebx+8), &p, sizeof(DWORD), &old); // 重置目标进程运行环境中的基址
peH->OptionalHeader.ImageBase = (unsigned long)p;
if(WriteProcessMemory(res, p, Ptr, ImageSize, &old)){// 复制PE数据到目标进程
Ctx.ContextFlags = CONTEXT_FULL;
if((unsigned long)p == Addr)
Ctx.Eax = peH->OptionalHeader.ImageBase + peH->OptionalHeader.AddressOfEntryPoint; // 重置运行环境中的入口地址
else
Ctx.Eax = (unsigned long)p + peH->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(Thrd, &Ctx);// 更新运行环境
ResumeThread(Thrd);// 执行
CloseHandle(Thrd);
}
else{// 加载失败,杀掉外壳进程
TerminateProcess(res, 0);
CloseHandle(Thrd);
CloseHandle(res);
res = INVALID_HANDLE_VALUE;
}
}
else{// 加载失败,杀掉外壳进程
TerminateProcess(res, 0);
CloseHandle(Thrd);
CloseHandle(res);
res = INVALID_HANDLE_VALUE;
}
}
delete[] s;
return res;
}




/*******************************************************\
{ ******************************************************* }
{ * 从内存中加载并运行exe * }
{ ******************************************************* }
{ * 参数: }
{ * Buffer: 内存中的exe地址 }
{ * Len: 内存中exe占用长度 }
{ * CmdParam: 命令行参数(不包含exe文件名的剩余命令行参数)}
{ * ProcessId: 返回的进程Id }
{ * 返回值: 如果成功则返回进程的Handle(ProcessHandle), }
{ 如果失败则返回INVALID_HANDLE_VALUE }
{ ******************************************************* }
\*******************************************************/
HANDLE MemExecute(void *ABuffer, long Len, char *CmdParam, unsigned long *ProcessId)
{
HANDLE res = INVALID_HANDLE_VALUE;
PIMAGE_NT_HEADERS peH;
PIMAGE_SECTION_HEADERS peSecH;
void *Ptr;
unsigned long peSz;
if(AlignPEToMem(ABuffer, Len, peH, peSecH, Ptr, peSz))
{
res = AttachPE(CmdParam, peH, peSecH, Ptr, peSz, *ProcessId);
VirtualFree(Ptr, peSz, MEM_DECOMMIT);
}
return res;
}

// 初始化
class CInit
{
public:
CInit()
{
MyVirtualAllocEx = (pfVirtualAllocEx)GetProcAddress(GetModuleHandle("Kernel32.dll"), "VirtualAllocEx");
}
}Init;




int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HANDLE hFile = NULL;
hFile = ::CreateFile( "f:\\SourceFromCsdn2.exe"
, FILE_ALL_ACCESS
, 0
, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
if( hFile == INVALID_HANDLE_VALUE )
return -1;

::SetFilePointer( hFile, 0, NULL, FILE_BEGIN);
DWORD dwFileSize = ::GetFileSize( hFile, NULL);

LPBYTE pBuf = new BYTE[dwFileSize];
memset( pBuf, 0, dwFileSize);

DWORD dwNumberOfBytesRead = 0;
::ReadFile( hFile
, pBuf
, dwFileSize
, &dwNumberOfBytesRead
, NULL
);

::CloseHandle(hFile);

unsigned long ulProcessId = 0;
MemExecute( pBuf, dwFileSize, "", &ulProcessId);
delete[] pBuf;


return 0;
}







2016-6-5 19:30
0
雪    币: 27
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
改基址后把重定位项也有一一对应的修改掉,对应的绝对地址要加上你修改过后地址的偏移量。也就是说之前你的exe加载基址是0x4000000,现在你要修改为0x6000000,那么程序中原有的绝对地址你都要加0x2000000,不然程序找不到以前数据的位置,肯定崩溃
2016-6-9 23:00
0
游客
登录 | 注册 方可回帖
返回
//