在内存中运行可执行程序,好处是可以给程序加壳,加密源程序,静态反汇编无法获得PE输入节,但是因为运行后仍然是独立的进程,所以没办法防止远程线程注入,挂接API钩子。
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[i]
->
PointerToRawData
+
peSecH[i]
->
SizeOfRawData
>
FileLen)
{
return
0
;
}
else
if
(peSecH[i]
->
VirtualAddress)
//
计算对齐后某节的大小
{
if
(peSecH[i]
->
Misc.VirtualSize)
{
res
=
GetAlignedSize( peSecH[i]
->
VirtualAddress
+
peSecH[i]
->
Misc.VirtualSize
, peH
->
OptionalHeader.SectionAlignment);
}
else
{
res
=
GetAlignedSize( peSecH[i]
->
VirtualAddress
+
peSecH[i]
->
SizeOfRawData
, peH
->
OptionalHeader.SectionAlignment);
}
}
else
if
( peSecH[i]
->
Misc.VirtualSize
<
peSecH[i]
->
SizeOfRawData )
{
res
+=
GetAlignedSize( peSecH[i]
->
SizeOfRawData
, peH
->
OptionalHeader.SectionAlignment);
}
else
{
res
+=
GetAlignedSize( peSecH[i]
->
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[i]
->
PointerToRawData)
&&
(SrcPeSecH[i]
->
PointerToRawData
<
l) )
{
l
=
SrcPeSecH[i]
->
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[i]
->
VirtualAddress)
Pt
=
(
void
*
)((unsigned
long
)Mem
+
peSecH[i]
->
VirtualAddress);
if
(peSecH[i]
->
SizeOfRawData)
{
//
复制数据到内存
memmove(Pt, (
const
void
*
)((unsigned
long
)(SrcMz)
+
peSecH[i]
->
PointerToRawData), peSecH[i]
->
SizeOfRawData);
if
(peSecH[i]
->
Misc.VirtualSize
<
peSecH[i]
->
SizeOfRawData)
Pt
=
(
void
*
)((unsigned
long
)Pt
+
GetAlignedSize(peSecH[i]
->
SizeOfRawData, peH
->
OptionalHeader.SectionAlignment));
else
//
pt 定位到下一节开始位置
Pt
=
(
void
*
)((unsigned
long
)Pt
+
GetAlignedSize(peSecH[i]
->
Misc.VirtualSize, peH
->
OptionalHeader.SectionAlignment));
}
else
{
Pt
=
(
void
*
)((unsigned
long
)Pt
+
GetAlignedSize(peSecH[i]
->
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
main(
int
argc,
char
*
argv[])
{
FILE
*
fp;
fp
=
fopen(
"
E:\\CProject\\DBGVIEW.EXE
"
,
"
rb
"
);
if
( fp )
{
fseek(fp,
0l
,SEEK_END);
int
file_size
=
ftell(fp);
/**/
/*
获取文件长度
*/
fseek(fp,
0l
,SEEK_SET);
/**/
/*
回到文件头部
*/
LPBYTE pBuf
=
new
BYTE[file_size];
memset( pBuf,
0
, file_size);
fread(pBuf,file_size,
1
,fp);
DWORD id
=
GetCurrentProcessId();
unsigned
long
ulProcessId
=
0
;
MemExecute( pBuf, file_size,
""
,
&
ulProcessId);
delete[] pBuf;
}
return
0
;
}