您的位置:首页 > 其它

在内存中运行可执行程序(转)

2016-05-26 16:50 218 查看
在内存中运行可执行程序,好处是可以给程序加壳,加密源程序,静态反汇编无法获得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] -> SizeOfRawDat
if (peSecH[i] -> Misc.VirtualSize  <  peSecH[i] -> SizeOfRawData)
Pt  =  ( void   * )((unsigned  long )Pt  +  GetAlignedSize(peSecH[i] -> SizeOfRawData, peH -> OptionalHeader.SectionAligent));
else   //  pt 定位到下一节开始位置
Pt  =  ( void   * )((unsigned  long )Pt  +  GetAlignedSize(peSecH[i] -> Misc.VirtualSize, peH -> OptionalHeader.SectionAlient));
}
else
{
Pt  =  ( void   * )((unsigned  long )Pt  +  GetAlignedSize(peSecH[i] -> Misc.VirtualSize, peH -> OptionalHeader.SectionAlignm));
}
}
}
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

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  |  MECOMMIT, PAGE_EXECUTE_READWRITE);
}
if ((p  ==  NULL)  &&  HasRelocationTable(peH))  { //  分配内存失败并且目标进程支持重定向
p  =  MyVirtualAllocEx((unsigned  long )res, NULL, ImageSize, MEM_RESERVE  |  MEM_COMMIT, PAGE_EXECUTE_READWRIT
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 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: