- implementation
-
- uses 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;
- begin
-
- end;
-
- {实现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;
-
- interface
- uses 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的