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的