PE头的应用---插入代码到EXE或DLL文件中

来源:互联网 发布:淘宝助理导入csv文件 编辑:程序博客网 时间:2024/05/17 06:24
 

三、代码实现(DELPHI版本),采用第三种方式实现代码插入。

 1. 定义两个类,一个用来实现在内存中建立输入表;一个用来实现对PE头的代码插入。

DelphiCode:
const MAX_SECTION_NUM = 20;const DYN_LOADER_START_MAGIC  = $C0DE51A9;const DYN_LOADER_END_MAGIC      = $C0DEE2DE;const DYN_LOADER_START_DATA1  = $DA1EDA1E;const IMPORT_TABLE_EXE = 0;const IMPORT_TABLE_DLL = 1;Type  TIIDUnion = record    case Integer of      0: (Characteristics: DWORD);            // 0 for terminating null import descriptor      1: (OriginalFirstThunk: DWORD);      // RVA to original unbound IAT (PIMAGE_THUNK_DATA)  end;  PIMAGE_IMPORT_DESCRIPTOR = ^IMAGE_IMPORT_DESCRIPTOR;  {$EXTERNALSYM PIMAGE_IMPORT_DESCRIPTOR}  _IMAGE_IMPORT_DESCRIPTOR = record    Union: TIIDUnion;    TimeDateStamp: DWORD;                      ForwarderChain: DWORD;                     Name: DWORD;    FirstThunk: DWORD;                       end;  {$EXTERNALSYM _IMAGE_IMPORT_DESCRIPTOR}  IMAGE_IMPORT_DESCRIPTOR = _IMAGE_IMPORT_DESCRIPTOR;  {$EXTERNALSYM IMAGE_IMPORT_DESCRIPTOR}  TImageImportDecriptor = IMAGE_IMPORT_DESCRIPTOR;  PImageImportDecriptor = PIMAGE_IMPORT_DESCRIPTOR;  PIMAGE_TLS_DIRECTORY32 = ^IMAGE_TLS_DIRECTORY32;  {$EXTERNALSYM PIMAGE_TLS_DIRECTORY32}  _IMAGE_TLS_DIRECTORY32 = record    StartAddressOfRawData: DWORD;    EndAddressOfRawData: DWORD;    AddressOfIndex: DWORD;                AddressOfCallBacks: DWORD;             SizeOfZeroFill: DWORD;    Characteristics: DWORD;  end;  {$EXTERNALSYM _IMAGE_TLS_DIRECTORY32}  IMAGE_TLS_DIRECTORY32 = _IMAGE_TLS_DIRECTORY32;  {$EXTERNALSYM IMAGE_TLS_DIRECTORY32}  TImageTlsDirectory32 = IMAGE_TLS_DIRECTORY32;  PImageTlsDirectory32 = PIMAGE_TLS_DIRECTORY32;  PImageImport = ^TImageImport;  TImageImport = packed record   szLibrary     : array[0..31] of char;   ThunksList : TList;  end;  {在内存中建立一个输入表的内存块,地址放在pMem中,大小是dwSize}  TImportTableMaker = class   private    function GetIATSize : DWORD;    procedure Init(iType : integer);   protected    ImportTable : TList;   public    dwSize : DWORD;    pMem   : Pointer;    constructor Create(iType : integer);    destructor Destroy; override;    procedure Build(baseRVA : DWORD);  end;{用来传递数据的一个结构}PData = ^TData; TData = record  dwReserved1           : DWORD;        dwFileType                : DWORD;  dwImageBase          : DWORD;        dwOrgEntryPoint      : DWORD;    dwImportVAddr         : DWORD;  dwRelocationVAddr : DWORD;  dwRelocationSize    : DWORD;  imgTLSDirectory      : IMAGE_TLS_DIRECTORY32; end;  TPE = class   private    dwFileSize           : DWORD;    pMem                   : Pointer;    SectionNum        : integer;    pNewSection       : Pointer;    function ReturnToBytePtr(FuncCode : pointer; findstr : DWORD): pointer;    procedure SetSectionsWritePermission;    procedure CopyData(dwVirtualAddress : DWORD);   protected    ITMaker                    : TImportTableMaker;    imgDosHeader          : TImageDosHeader;    pDosStub                    : Pointer;    dwDosStubSize         : DWORD;    dwDosStubOffset      : DWORD;    imgNtHeaders           : TImageNtHeaders;    imgSectionHeaders : array[0..MAX_SECTION_NUM -1] of TImageSectionHeader;    imgSections               : array[0..MAX_SECTION_NUM -1] of Pointer;    imgTLSDirectory        : IMAGE_TLS_DIRECTORY32;    function PEAlign(dwTarNum : DWORD; dwAlignTo : DWORD) : DWORD;    procedure AlignmentSections;    function Offset2RVA(dwOffset : DWORD) : DWORD;    function RVA2Offset(dwRVA : DWORD) : DWORD;    function ImgRVA2Section(dwRVA : DWORD) : PImageSectionHeader;    function ImgOffset2Section(dwOffset: DWORD): PImageSectionHeader;    function ImgOffset2SectionNum(dwOffset: DWORD): integer;    function AddNewSection(szName: string; dwSize: DWORD): PImageSectionHeader;   public    constructor Create;    destructor Destroy; override;    procedure OpenFile(filename : string);    procedure SaveFile(filename : string);    procedure CyrptFile;  end;

二、类代码

DelphiCode:
implementationuses PEInit;   //被用来插入的代码单元const szWindowsAPIs : array[0..10] of string = ('Kernel32.dll',                                               'GetModuleHandleA',                                               'VirtualProtect',                                               'GetModuleFileNameA',                                               'CreateFileA',                                               'GlobalAlloc',                                               '',                                               'User32.dll',                                               'MessageBoxA',                                               '',                                               '');const szIATEXEStrings : array[0..4] of string = ('Kernel32.dll',                                                 'LoadLibraryA',                                                 'GetProcAddress',                                                 '',                                                 '');const szIATDLLStrings : array[0..29] of string = ( 'Kernel32.dll', 'LoadLibraryA', 'GetProcAddress', 'GetModuleHandleA', '', 'User32.dll', 'GetKeyboardType', 'WindowFromPoint', '', 'AdvApi32.dll', 'RegQueryValueExA', 'RegSetValueExA', 'StartServiceA', '', 'Oleaut32.dll', 'SysFreeString', 'CreateErrorInfo', 'SafeArrayPtrOfIndex', '', 'Gdi32.dll', 'UnrealizeObject', '', 'Ole32.dll', 'CreateStreamOnHGlobal', 'IsEqualGUID', '', 'ComCtl32.dll', 'ImageList_SetIconSize', '', '');constructor TPE.Create;begin dwDosStubSize := 0;end;destructor TPE.Destroy;beginend;{实现File或Section对齐}function TPE.PEAlign(dwTarNum: DWORD; dwAlignTo: DWORD): DWORD;begin result := ((dwTarNum + dwAlignTo - 1) div dwAlignTo) * dwAlignTo;end;{把所有的节进行Section对齐}procedure TPE.AlignmentSections;var i   : integer;begin for i:= 0 to imgNtHeaders.FileHeader.NumberOfSections - 1 do begin  imgSectionHeaders[i].VirtualAddress := PEAlign(imgSectionHeaders[i].VirtualAddress, imgNtHeaders.OptionalHeader.SectionAlignment);  imgSectionHeaders[i].Misc.VirtualSize := PEAlign(imgSectionHeaders[i].Misc.VirtualSize, imgNtHeaders.OptionalHeader.SectionAlignment);  imgSectionHeaders[i].PointerToRawData := PEAlign(imgSectionHeaders[i].PointerToRawData, imgNtHeaders.OptionalHeader.FileAlignment);  imgSectionHeaders[i].SizeOfRawData := PEAlign(imgSectionHeaders[i].SizeOfRawData, imgNtHeaders.OptionalHeader.FileAlignment); end; imgNtHeaders.OptionalHeader.SizeOfImage := imgSectionHeaders[i-1].VirtualAddress + imgSectionHeaders[i-1].Misc.VirtualSize; imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress := 0; imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size := 0; imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress := 0; imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size := 0; imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress := 0; imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size := 0;end;{找到内存中某一个RVA所映射的磁盘文件上的offset}function TPE.RVA2Offset(dwRVA : DWORD): DWORD;var offset : DWORD; section : PImageSectionHeader;begin section := ImgRVA2Section(dwRVA); if section = nil then  result := 0 else begin  offset := dwRVA + section.PointerToRawData - section.VirtualAddress;  result := offset; end;end;{找到磁盘上某一个offset所映射的内存中的RVA}function TPE.Offset2RVA(dwOffset : DWORD): DWORD;var section : PImageSectionHeader;begin section := ImgOffset2Section(dwOffset); if section = nil then  result := 0 else  result := dwOffset + section.VirtualAddress - section.PointerToRawData;end;{返回PE文件加载到内存后,RVA地址所处的Section}function TPE.imgRVA2Section(dwRVA : DWORD) : PImageSectionHeader;var i : integer;begin for i:= 0 to imgNtHeaders.FileHeader.NumberOfSections - 1 do begin  if ((dwRVA >= imgSectionHeaders[i].VirtualAddress) and (dwRVA <= (imgSectionHeaders[i].VirtualAddress + imgSectionHeaders[i].SizeOfRawData))) then  begin   result := @imgSectionHeaders[i];   exit;  end; end; result := nil;end;{返回OFFSET地址在PE文件位于磁盘上的所落的Section}function TPE.ImgOffset2Section(dwOffset : DWORD): PImageSectionHeader;var i: integer;begin for i:=0 to imgNtHeaders.FileHeader.NumberOfSections - 1 do begin  if ((dwOffset >= imgSectionHeaders[i].PointerToRawData) and (dwOffset < (imgSectionHeaders[i].PointerToRawData + imgSectionHeaders[i].SizeOfRawData))) then  begin   result := @ImgSectionHeaders[i];   exit;  end; end; result := nil;end;{返回Offset地址在PE文件位于磁盘上所落Section的编号}function TPE.ImgOffset2SectionNum(dwOffset : DWORD): integer;var i: integer;begin for i:=0 to imgNtHeaders.FileHeader.NumberOfSections - 1 do begin  if ((dwOffset >= imgSectionHeaders[i].PointerToRawData) and (dwOffset < (imgSectionHeaders[i].PointerToRawData + imgSectionHeaders[i].SizeOfRawData))) then  begin   result := i;   exit;  end; end; result := -1;end;{增加一个新的Section,可读/写, 包含已初始化数据.}function TPE.AddNewSection(szName: string; dwSize: DWORD): PImageSectionHeader;var i       : integer; roffset : DWORD; rsize   : DWORD; voffset : DWORD; vsize   : DWORD;begin i := imgNtHeaders.FileHeader.NumberOfSections; rsize := PEAlign(dwSize, imgNtHeaders.OptionalHeader.FileAlignment); vsize := PEAlign(rsize, imgNtHeaders.OptionalHeader.SectionAlignment); roffset := PEAlign(imgSectionHeaders[i-1].PointerToRawData + imgSectionHeaders[i-1].SizeOfRawData,                    imgNtHeaders.OptionalHeader.FileAlignment); voffset := PEAlign(imgSectionHeaders[i-1].VirtualAddress + imgSectionHeaders[i-1].Misc.VirtualSize,                    imgNtHeaders.OptionalHeader.SectionAlignment); FillChar(imgSectionHeaders[i],sizeof(TImageSectionHeader),#0); imgSectionHeaders[i].PointerToRawData := roffset; imgSectionHeaders[i].VirtualAddress := voffset; imgSectionHeaders[i].SizeOfRawData := rsize; imgSectionHeaders[i].Misc.VirtualSize := vsize; imgSectionHeaders[i].Characteristics := $C0000040;  CopyMemory(@imgSectionHeaders[i].Name[0],@szName[1],length(szName)); imgSections[i] := Pointer(GLobalAlloc(GMEM_FIXED or GMEM_ZEROINIT,rsize));  imgNtHeaders.FileHeader.NumberOfSections := imgNtHeaders.FileHeader.NumberOfSections + 1; result := @imgSectionHeaders[i];end;{打开一个PE文件,按其格式分部分读入}procedure TPE.OpenFile(filename : string);var dwBytesRead        : DWORD; hFile              : THANDLE; sectionNum         : DWORD; i                  : integer; firstSectionOffset : DWORD; dwOffset           : DWORD;begin pMem := nil; hFile := CreateFile(PChar(filename),GENERIC_READ, FILE_SHARE_WRITE or FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0); if hFile = INVALID_HANDLE_VALUE then begin  exit; end; dwFileSize := GetFileSize(hFile,0); if dwFileSize = 0 then begin  CloseHandle(hFile);  exit; end; pMem := Pointer(GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT, dwFileSize)); if dwFileSize = 0 then begin  CloseHandle(hFile);  exit; end; ReadFile(hFile,pMem^,dwFileSize,dwBytesRead,nil); CloseHandle(hFile); CopyMemory(@imgDosHeader,pMem,sizeof(IMAGE_DOS_HEADER)); dwDosStubSize := imgDosHeader._lfanew - sizeof(IMAGE_DOS_HEADER); dwDosStubOffset := sizeof(IMAGE_DOS_HEADER); getMem(pDosStub,dwDosStubSize); if (dwDosStubSize and $80000000) = $00000000 then begin  copyMemory(pDosStub,pointer(DWORD(pMem) + dwDosStubOffset), dwDosStubSize); end; copyMemory(@imgNtHeaders,pointer(DWORD(pMem)+imgDosHeader._lfanew),sizeof(IMAGE_NT_HEADERS)); firstSectionOffset := imgDosHeader._lfanew + sizeof(IMAGE_NT_HEADERS); if imgDosHeader.e_magic <> IMAGE_DOS_SIGNATURE then begin  GlobalFree(DWORD(pMem));  exit; end; SectionNum := imgNtHeaders.FileHeader.NumberOfSections; for i:=0 to SectionNum -1 do begin  CopyMemory(@imgSectionHeaders[i],pointer(DWORD(pMem)+ firstSectionOffset + i * sizeof(IMAGE_SECTION_HEADER)),sizeof(IMAGE_SECTION_HEADER)); end; for i:=0 to SectionNum -1 do begin  imgSections[i] := Pointer(GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT,PEAlign(imgSectionHeaders[i].SizeOfRawData,imgNtHeaders.OptionalHeader.FileAlignment)));  copyMemory(imgSections[i],pointer(DWORD(pMem)+imgSectionHeaders[i].PointerToRawData), imgSectionHeaders[i].SizeOfRawData); end; if imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress <> 0 then begin  dwOffset := RVA2Offset(imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);  copymemory(@imgTLSDirectory,pointer(DWORD(pMem) + dwOffset), sizeof(IMAGE_TLS_DIRECTORY32)); end; GlobalFree(DWORD(pMem));end;procedure TPE.SaveFile(filename : string);var dwBytesWritten : DWORD; i              : integer; dwRO_first_section : DWORD; sectionNum : DWORD; hFile : THANDLE;begin hFile := CreateFile(PChar(filename),GENERIC_WRITE, FILE_SHARE_WRITE or FILE_SHARE_READ, nil, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); if hFile = INVALID_HANDLE_VALUE then begin  hFile := CreateFile(PChar(filename), GENERIC_WRITE, FILE_SHARE_WRITE or FILE_SHARE_READ, nil, CREATE_NEW, FILE_ATTRIBUTE_NORMAL,0);  if hFile = INVALID_HANDLE_VALUE then   exit; end; AlignmentSections; i := imgNtHeaders.FileHeader.NumberOfSections; dwFileSize := imgSectionHeaders[i-1].PointerToRawData + imgSectionHeaders[i-1].SizeOfRawData; pMem := Pointer(GlobalAlloc(GMEM_FIXED or GMEM_ZEROINIT,dwFileSize)); if pMem = nil then begin  CloseHandle(hFile);  exit; end; copyMemory(pMem,@imgDosHeader,sizeof(IMAGE_DOS_HEADER)); if (dwDOSStubSize and $80000000) = $00000000 then  copyMemory(pointer(DWORD(pMem) + dwDosStubOffset), pDosStub, dwDosStubSize); copyMemory(pointer(DWORD(pMem)+imgDosHeader._lfanew), @imgNtHeaders, sizeof(IMAGE_NT_HEADERS)); dwRO_first_section := imgDosHeader._lfanew + sizeof(IMAGE_NT_HEADERS); sectionNum := imgNtHeaders.FileHeader.NumberOfSections; for i:=0 to SectionNum - 1 do begin  CopyMemory(pointer(DWORD(pMem) + dwRO_first_Section + i * sizeof(IMAGE_SECTION_HEADER)), @imgSectionHeaders[i],sizeof(IMAGE_SECTION_HEADER)); end; for i:=0 to SectionNum - 1 do begin  CopyMemory(pointer(DWORD(pMem) + imgSectionHeaders[i].PointerToRawData), imgSections[i], ImgSectionHeaders[i].SizeOfRawData); end; SetFilePointer(hFile ,0, nil,FILE_BEGIN); writeFile(hFile,pMem^,dwFileSize, dwBytesWritten,nil); setFilePointer(hFile,dwFileSize, nil,FILE_BEGIN); setEndOfFile(hFile); CloseHandle(hFile); GlobalFree(DWORD(pMem));end;{用来查找一段代码的标志位,在FuncCode指针开始的字符串中,查找一个DWORD的标志}function TPE.ReturnToBytePtr(FuncCode : pointer; findstr : DWORD): pointer;var tmpd : Pointer;begin asm       pushad       mov eax, FuncCode       jmp @label1  @label0:       inc eax  @label1:       mov ebx, [eax]       cmp ebx, findstr       jnz @label0       mov tmpd, eax       popad end; result := tmpd;end;{把一段跳转指令加入到PE文件中,先建立一个新SECTION,然后把新输入表放入新区的     }{ 起始地址,把一点代码放到输入表后.然后把跳转指令加入到新Section,跳回原来的程序,}{同时使用新的输入表来取代旧的输入表 }procedure TPE.CyrptFile;var ch_temp          : Pointer; i                : DWORD; imgSectionHeader : PImageSectionHeader; dwNewSectionSize : DWORD; dwCodeSize       : DWORD; dwCodeOffset     : DWORD;begin if (imgNTHeaders.FileHeader.Characteristics and IMAGE_FILE_DLL) = IMAGE_FILE_DLL then  ITMaker := TImportTableMaker.Create(IMPORT_TABLE_DLL) else  ITMaker := TImportTableMaker.Create(IMPORT_TABLE_EXE); ch_temp := Pointer(DWORD(ReturnToBytePtr(@InitPE,DYN_LOADER_START_MAGIC)) +4); dwCodeSize := DWORD(ReturnToBytePtr(@InitPE,DYN_LOADER_END_MAGIC)) - DWORD(ch_temp); dwCodeOffset := ITMaker.dwSize; dwNewSectionSize := dwCodeSize + ITMaker.dwSize; getmem(pNewSection,dwNewSectionSize); copymemory(Pointer(DWORD(pNewSection) + dwCodeOffset), ch_temp, dwCodeSize); imgSectionHeader := AddNewSection('.xxx',dwNewSectionSize); CopyData(imgSectionHeader.VirtualAddress); ITMaker.Build(imgSectionHeader.VirtualAddress); copyMemory(pNewSection,ITMaker.pMem, ITMaker.dwSize); copymemory(imgSections[imgNtHeaders.FileHeader.NumberOfSections-1], pNewSection, dwNewSectionSize); imgNtHeaders.OptionalHeader.AddressOfEntryPoint := imgSectionHeader.VirtualAddress + dwCodeOffset; imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress := imgSectionHeader.VirtualAddress; imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size := ITMaker.dwSize; imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress := 0; imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size := 0; SetSectionsWritePermission; freemem(pNewSection,dwNewSectionSize); ITMaker.Free;end;procedure TPE.CopyData(dwVirtualAddress : DWORD);var i         : integer; APINum    : integer; pData     : Pointer; dwOffset  : DWORD; len       : longint; DataTable : TData; temp      : byte;begin DataTable.dwReserved1 := $CCCCCCCC; if ((imgNtHeaders.FileHeader.Characteristics and IMAGE_FILE_DLL) = IMAGE_FILE_DLL) then  DataTable.dwFileType := IMPORT_TABLE_DLL else  DataTable.dwFileType := IMPORT_TABLE_EXE; DataTable.dwImageBase := imgNtHeaders.OptionalHeader.ImageBase; DataTable.dwOrgEntryPoint := imgNtHeaders.OptionalHeader.AddressOfEntryPoint; DataTable.dwImportVAddr := imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; if (imgNtHeaders.FileHeader.Characteristics and IMAGE_FILE_DLL) = IMAGE_FILE_DLL then begin  DataTable.dwRelocationVAddr := imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;  DataTable.dwRelocationSize  := imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; end; pData := ReturnToBytePtr(pNewSection, DYN_LOADER_START_DATA1); if imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress <> 0 then begin  CopyMemory(@DataTable.imgTLSDirectory,@imgTLSDirectory,sizeof(IMAGE_TLS_DIRECTORY32));  dwOffset := DWORD(pData) - DWORD(pNewSection);  dwOffset := dwOffset + sizeof(DataTable) - sizeof(IMAGE_TLS_DIRECTORY32);  imgNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress := dwVirtualAddress + dwOffset; end; CopyMemory(pData,@DataTable, sizeof(TData)); dwOffset := sizeof(TDATA); i := 0; APINum := 0; temp := 0; repeat  len := Length(szWindowsAPIs[i]) + 1;  CopyMemory(Pointer(DWORD(pData) + dwOffset),@szWindowsAPIs[i][1],len);  dwOffset := dwOffset + len;  repeat   i := i + 1;   if szWindowsAPIs[i] <> '' then   begin    len := length(szWindowsAPIs[i]) + 1;    CopyMemory(Pointer(DWORD(pData) + dwOffset), @szWindowsAPIs[i][1],len);    dwOffset := dwOffset + len;    APINum := APINum + 1;   end   else   begin    CopyMemory(Pointer(DWORD(pData) + dwOffset), @temp, 1);    dwOffset := dwOffset + 1;   end;  until szWindowsAPIs[i] = '';  i := i + 1; until szWindowsAPIs[i] = '';end;procedure TPE.SetSectionsWritePermission;var i  : integer;begin for i:=0 to imgNTHeaders.FileHeader.NumberOfSections - 1 do   imgSectionHeaders[i].Characteristics := $C0000040;end;{******************************************************************************}                                                constructor TImportTableMaker.Create(iType : integer);begin ImportTable := TList.Create; init(iType); dwSize := GetIATSize; GetMem(pMem,dwSize);end;destructor TImportTableMaker.Destroy;var imgImport : PImageImport;begin while ImportTable.Count > 0 do begin  imgImport := PImageImport(ImportTable.Items[0]);  while imgImport.ThunksList.Count > 0 do  begin   freeMem(imgImport.ThunksList.Items[0],32);   imgImport.ThunksList.Delete(0);  end;  imgImport.ThunksList.Free;  dispose(imgImport);  ImportTable.Delete(0); end; ImportTable.Free; FreeMem(pMem,dwSize);end;procedure TImportTableMaker.Init(iType : integer);var i         : integer; IATString : pointer; imgImport : PImageImport; imgThunk  : PChar; function IsStringsEnd(inx : integer) : boolean; begin   result := false;   case iType of    IMPORT_TABLE_EXE:          begin           if szIATEXEStrings[inx] = '' then            result := true;          end;    IMPORT_TABLE_DLL:          begin           if szIATDLLStrings[inx] = '' then            result := true;          end;   end; end;begin i := 0; repeat  New(imgImport);  imgImport.ThunksList := TList.Create;  case iType of   IMPORT_TABLE_EXE:   copyMemory(@imgImport.szLibrary[0], @szIATEXEStrings[i][1],32);   IMPORT_TABLE_DLL:   copyMemory(@imgImport.szLibrary[0], @szIATDLLStrings[i][1],32);  end;  repeat   i := i + 1;   if not IsStringsEnd(i) then   begin    getMem(imgThunk,32);    fillchar(imgTHunk^,32,#0);    case iType of     IMPORT_TABLE_EXE:  copyMemory(imgThunk,@szIATEXEStrings[i][1],32);     IMPORT_TABLE_DLL:  copyMemory(imgThunk,@szIATDLLStrings[i][1],32);    end;    imgImport.ThunksList.Add(imgThunk);   end;  until IsStringsEnd(i);  ImportTable.Add(imgImport);  i := i + 1; until IsStringsEnd(i);end;function TImportTableMaker.GetIATSize : DWORD;var i        : integer; j        : integer; dwDLLNum : DWORD; dwFuncNum : DWORD; dwszDLLSize : DWORD; dwszFuncSize : DWORD; dwImportSize : DWORD; imgImport    : PImageImport;begin dwDLLNum := 0; dwFuncNum := 0; dwszDLLSize := 0; dwszFuncSize := 0; dwImportSize := 0; for i:= 0 to ImportTable.Count - 1 do begin  imgImport := ImportTable.Items[i];  dwszDLLSize := dwszDLLSize + strlen(imgimport.szLibrary) + 1;  for j:=0 to imgImport.ThunksList.Count - 1 do  begin   dwszFuncSize := dwszFuncSize + 2 + strlen(PChar(imgimport.ThunksList.Items[j])) + 1;   dwFuncNum := dwFuncNum + 1;  end;  dwFuncNum := dwFuncNum + 1;  dwDLLNum  := dwDLLNum + 1; end; dwDLLNum := dwDLLNum + 1; dwImportSize := dwDLLnum * 20 + dwFuncNum * 4 + dwSzDLLSize + dwszFuncSize; result := dwImportSize;end;procedure TImportTableMaker.Build(baseRVA : DWORD);var i             : integer; j             : integer; pITBaseRVA   : DWORD; temp          : DWORD; dwDLLNum      : DWORD; dwDLLName     : DWORD; dwDLLFirst    : DWORD; dwszDLLSize   : DWORD; dwIIDNum      : DWORD; dwFunNum      : DWORD; dwFunFirst    : DWORD; dwszFuncSize  : DWORD; dwFirstThunk  : DWORD; dwImportSize  : DWORD; imgImport     : PImageImport; importDesc    : TImageImportDecriptor;begin pITBaseRVA := baseRVA;     importDesc.Union.OriginalFirstThunk := 0; importDesc.TimeDateStamp := 0; importDesc.ForwarderChain := 0; importDesc.Name := 0; importDesc.FirstThunk := 0; dwDLLNum := 0; dwDLLName := 0; dwDLLFirst := 0; dwszDLLSize := 0; dwIIDNum := 0; dwFunNum := 0; dwFunFirst := 0; dwszFuncSize := 0; dwFirstThunk := 0; dwImportSize := 0; for i:= 0 to importTable.Count -1 do begin  imgImport := PImageImport(importTable.Items[i]);  dwszDLLSize := dwszDLLSize + strlen(imgImport.szLibrary) + 1;    for j:= 0 to imgImport.ThunksList.Count - 1 do  begin   dwszFuncSize := dwszFuncSize + 2 + strlen(PChar(imgImport.ThunksList.Items[j])) + 1;   dwFunNum := dwFunNum + 1;  end;  dwFunNum := dwFunNum + 1;  dwDLLNum := dwDLLNum + 1; end; dwDLLNum := dwDLLNum + 1; dwImportSize := dwDLLNum * 20 + dwFunNum * 4 + dwszDLLSize + dwszFuncSize; FillMemory(pMem,dwImportSize, 0); dwFirstThunk := dwDLLNum * 20;               dwDLLFirst := dwDLLNum * 20 + dwFunNum * 4;   dwFunFirst := dwDLLNum * 20 + dwFunNum * 4 + dwszDLLSize;   for i := 0 to importTable.Count - 1 do begin  imgImport := importTable.Items[i];  importDesc.Name := pITBaseRVA + dwDLLFirst;  importDesc.FirstThunk := pITBaseRVA  + dwFirstThunk;  CopyMemory(Pointer(DWORD(pMem) + dwIIDNum * sizeof(IMAGE_IMPORT_DESCRIPTOR)),@importDesc,sizeof(IMAGE_IMPORT_DESCRIPTOR));  CopyMemory(Pointer(DWORD(pMem) + dwDLLFirst),@imgImport.szLibrary[0],strlen(imgImport.szLibrary) + 1);  for j:=0 to imgimport.ThunksList.Count - 1 do  begin   temp := pITBaseRVA + dwFunFirst;   CopyMemory(Pointer(DWORD(pMem) + dwFirstThunk),@temp,4);   CopyMemory(Pointer(DWORD(pMem) + dwFunFirst + 2), PChar(imgImport.ThunksList.Items[j]),strlen(imgImport.ThunksList.Items[j]) + 1);   dwFunFirst := dwFunFirst + 2 + strlen(imgImport.ThunksList.Items[j]) + 1;   dwFirstThunk := dwFirstThunk + 4;  end;  temp := 0;  CopyMemory(Pointer(DWORD(pMem) + dwFirstThunk),@temp, 4);  dwFirstThunk := dwFirstTHunk + 4;  dwDLLFirst := dwDLLFirst + strlen(imgImport.szLibrary) + 1;  dwIIDNum := dwIIDNum + 1; end; importDesc.Name := 0; importDesc.FirstThunk := 0; CopyMemory(Pointer(DWORD(pMem)+dwIIDNum * sizeof(IMAGE_IMPORT_DESCRIPTOR)), @importDesc,sizeof(IMAGE_IMPORT_DESCRIPTOR));end;end.{************************************************************************************************************}PEint单元unit PEInit;interfaceuses windows;procedure InitPE; stdcall;implementation{一段要嵌入到PE文件中的指令}{标志位的作用是用来找到找到从开始标志位后到结束标志位之间的指令大小及开始地址}{这段代码如果用在VC中,则要设置链接选项/INCREMENTAL LINK OFF}procedure InitPE; stdcall;begin asm  {开始标志位}  DB $A9 DB $51 DB $DE DB $C0@Main_0:  pushad;  call @Main_1@Main_1:  pop ebp  sub ebp, offset @main_1   {**********************支持DLL,OCX等****************************************}@_support_dll_0:  jmp @_support_dll_1 {// nop; nop; // in the secon time OEP  第一次加载后,}                                          {这句会被改成 nop; nop;在DLL被卸载的时候,会直接调用jmp @_support_dll_2}  jmp @_support_dll_2@_support_dll_1:                            test [ebp + @_p_dwFileType],0001h  // IMPORT_TABLE_DLL  jz @_no_dll_pe_file_0  mov eax,[esp+24h]                   mov ebx,[esp+34h]                   cmp eax,ebx                         ja @_no_dll_pe_file_0  cmp word ptr [eax], IMAGE_DOS_SIGNATURE  jne @_no_dll_pe_file_0                    mov [ebp + @_RO_dwImageBase],eax       @_no_dll_pe_file_0:  // 获取输入表中的LoadLibrary 和 GetProcAddress来建立函数跳转表  mov eax, DWORD PTR [ebp + @_RO_dwImageBase]   add eax, [eax + 03Ch]    add eax, 080h                  mov ecx, [eax]   add ecx, [ebp + @_RO_dwImageBase]   add ecx, 010h   mov eax, [ecx]  add eax, [ebp + @_RO_dwImageBase]   mov ebx, [eax]   mov [ebp + @_p_LoadLibrary],ebx    add eax, 04h  mov ebx, [eax]  mov [ebp + @_p_GetProcAddress], ebx  call @_api_load  // 加载插入功能代码所需要的DLL和函数跳转表  //***************************功能性代码***************************************  push MB_OK or MB_ICONINFORMATION  lea eax,[ebp + @_p_szCaption]  push eax  lea eax,[ebp + @_p_szText]  push eax  push 0000h  call @_jmp_MessageBox  //****************************************************************************  {将在内存中的PE文件的NTHeader头改为可读写}       mov edi, [ebp + @_RO_dwImageBase]  add edi, [edi + 03Ch]  lea eax, [ebp + @_p_ptempbuffer]   push eax  push PAGE_READWRITE                push [edi + 54h]                   push [ebp + @_RO_dwImageBase]      call @_jmp_VirtualProtect         call @_it_fixup                  // 为被插入的程序建立内存中的输入表  {判断是否是DLL}  mov edi,[ebp + @_RO_dwImageBase]  add edi,[edi+03Ch]  mov ax,word ptr [edi+016h]                              test ax,IMAGE_FILE_DLL  jz @_no_dll_pe_file_1  call @_reloc_fixup              // 为被捆绑的程序修正重定位表.因为EXE一般不需要,只在DLL的时候需要。  mov ax,9090h                    // 为DLL建立卸载时候的入口点  mov word ptr [ebp + @_support_dll_0],ax@_no_dll_pe_file_1:@_support_dll_2://--------- 利用SEH异常转入程序入口点 ---------  mov eax, [ebp + @_RO_dwImageBase]  add eax, DWORD PTR [ebp + @_RO_dwOrgEntryPoint]  mov DWORD PTR [esp + 10h], eax  lea eax, [ebp + @_except_handler1_oep_jump]  mov DWORD PTR [esp + 1ch],eax  popad  push eax  xor eax,eax  push DWORD PTR FS:[0]  mov DWORD PTR FS:[0], ESP  {注册完异常处理回调函数,开始调用INT 3 触发异常,异常发生后,}  {线程的栈被保护起来,原来存有真正OEP地址的EBX也被保存起来}  DB $CC  DB $CC  DB $CC  DB $CC{eax中返回字符串的长度}@_strlen:  push ebp  mov ebp,esp  push ecx  push esi  push ebx  mov esi,[ebp+08h]  mov ecx,255// -> Length  xor ebx,ebx@_strlenloop:  lods byte ptr ds:[esi]  cmp al,00h  jz @_endbufstrlen  inc ebx  loop @_strlenloop@_endbufstrlen:  mov eax,ebx  inc eax  pop ebx  pop esi  pop ecx  mov esp,ebp  pop ebp  ret{*********************为被插入代码的程序修正重定位表*******************************}@_reloc_fixup: mov eax,[ebp + @_RO_dwImageBase] mov edx,eax mov ebx,eax add ebx,[ebx+3Ch]      mov ebx,[ebx+034h]     sub edx,ebx            je @_reloc_fixup_end    mov ebx,[ebp + @_p_dwRelocationVirtualAddress]  test ebx,ebx jz @_reloc_fixup_end                            add ebx,eax                                   @_reloc_fixup_block: mov eax,[ebx+004h]    test eax,eax jz @_reloc_fixup_end                     lea ecx,[eax-008h]    shr ecx,001h     lea edi,[ebx+008h]   @_reloc_fixup_do_entry: movzx eax,word ptr [edi]                 push edx mov edx,eax shr eax,00Ch             mov esi,[ebp + @_RO_dwImageBase]             and dx,00FFFh add esi,[ebx]            add esi,edx     pop edx@_reloc_fixup_HIGH:  dec eax  jnz @_reloc_fixup_LOW  mov eax,edx  shr eax,010h  //HIWORD(Delta)  jmp @_reloc_fixup_LOW_fixup@_reloc_fixup_LOW:  dec eax  jnz @_reloc_fixup_HIGHLOW  movzx eax,dx   //LOWORD(Delta)@_reloc_fixup_LOW_fixup:  add word ptr [esi],ax  jmp @_reloc_fixup_next_entry@_reloc_fixup_HIGHLOW:  dec eax  jnz @_reloc_fixup_next_entry  add [esi],edx@_reloc_fixup_next_entry:  inc edi  inc edi      //Entry++  loop @_reloc_fixup_do_entry@_reloc_fixup_next_base: add ebx,[ebx+004h]    //ImageBaseRelocation + ImageBaseRelocation.SizeOfBlock jmp @_reloc_fixup_block@_reloc_fixup_end: ret  {**************为捆绑的程序在内存中建立IAT表*********************************}  {1. 加载输入表中对应的DLL。                                                  }  {2. 加载输入表里对应DLL的输入函数。                                          }  {3. 讲函数的内存地址放入输入表的FirstThunk里,建立IAT表                      }@_it_fixup:  mov ebx,[ebp + @_p_dwImportVirtualAddress]    test ebx,ebx                                  jz @_it_fixup_end                   mov esi,[ebp + @_RO_dwImageBase]  add ebx,esi                        @_it_fixup_get_lib_address_loop:  mov eax,[ebx+00Ch]          test eax,eax                                 jz @_it_fixup_end                mov ecx,[ebx+010h]          add ecx,esi                                  mov [ebp + @_p_dwThunk],ecx         mov ecx,[ebx]           test ecx,ecx                                 jnz @_it_fixup_table                         mov ecx,[ebx + 010h]                      @_it_fixup_table:  add ecx,esi                                  mov [ebp + @_p_dwHintName],ecx        add eax,esi          push eax           mov eax,offset @_p_LoadLibrary  call [ebp+eax]         test eax,eax  jz @_it_fixup_end                          mov edi,eax                              @_it_fixup_get_proc_address_loop:  mov ecx,[ebp + @_p_dwHintName]       mov edx,[ecx]          test edx,edx                                jz @_it_fixup_next_module                   test edx,80000000h         jz @_it_fixup_by_name                       and edx,07FFFFFFFh         jmp @_it_fixup_get_addr@_it_fixup_by_name:  add edx,esi          inc edx                                     inc edx       @_it_fixup_get_addr:  push edx                 push edi          mov eax,offset @_p_GetProcAddress  call [ebp+eax]               mov ecx,[ebp + @_p_dwThunk]               mov [ecx],eax                              add dword ptr [ebp + @_p_dwThunk],004h   add dword ptr [ebp + @_p_dwHintName],004h       jmp @_it_fixup_get_proc_address_loop@_it_fixup_next_module:  add ebx,014h       jmp @_it_fixup_get_lib_address_loop@_it_fixup_end:  ret  {***************加载动态库,然后建立其输入函数的跳转表***********************}@_api_load:  lea edi, [ebp + @_p_szKernel32]          lea ebx, [ebp + @_p_GetModuleHandle]     lea ecx, [ebp + @_jmp_GetModuleHandle]   add ecx, 02h                          @_api_get_lib_address_loop:  push ecx                                 push edi                                 mov eax, offset @_p_LoadLibrary  call [ebp + eax]                         pop ecx                                 mov esi, eax                            push edi  call @_strlen  add  esp, 04h  add  edi, eax                         @_api_get_proc_address_loop:  push ecx                                 push edi                                 push esi                                 mov eax, offset @_p_GetProcAddress  call [ebp + eax]                         pop ecx                                  mov [ebx], eax                          mov [ecx], ebx                           add ebx, 04h                            add ecx, 06h                             push edi                                 call @_strlen  add esp, 04h  add edi, eax                             mov al, byte ptr [edi]                   test al,al  jnz @_api_get_proc_address_loop  inc edi  mov al, byte ptr [edi]  test al, al  jnz @_api_get_lib_address_loop  ret   {SEH异常处理回调函数的有四个参数,分别为ExceptionRecord, SEH, Context,       }  {DispatcherContext,先压入下一个指令的地址,然后根据被压入栈的这四个参数中    }  {Context的

四、测试。

可以对EXE文件和DLL文件进行代码插入。当被插入的EXE文件或DLL文件运行或被调用的时候,都会先跳出一个对话框:

然后再运行或调用被插入的EXE或DLL文件。

原创粉丝点击