如何在内存中运行可执行程序?
如何在内存中运行可执行程序?
在内存中运行可执行程序
在内存中运行可执行程序,好处是可以给程序加壳,加密源程序,静态反汇编无法获得PE输入节,但是因为运行后仍然是独立的进程,所以没办法防止远程线程注入,挂接API钩子。
typedefIMAGE_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_HEADERMzH
,unsigned long FileLen
,PIMAGE_NT_HEADERSpeH
,PIMAGE_SECTION_HEADERSpeSecH)
{
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到内存并对齐所有节
BOOLAlignPEToMem( void * Buf
, long Len
,PIMAGE_NT_HEADERS & peH
,PIMAGE_SECTION_HEADERS & peSecH
, void *& Mem
,unsigned long & ImageSize)
{
PIMAGE_DOS_HEADERSrcMz; // DOS头
PIMAGE_NT_HEADERSSrcPeH; // PE头
PIMAGE_SECTION_HEADERSSrcPeSecH; // 节表
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 );
pfVirtualAllocExMyVirtualAllocEx = NULL;
BOOLIsNT()
{
return MyVirtualAllocEx != NULL;
}
// 生成外壳程序命令行
char * PrepareShellExe( char * CmdParam,unsigned long BaseAddr,unsigned long Ima