三、代码实现(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:

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的

四、测试。

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

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

http://blog.csdn.net/suiyunonghen/article/details/3860206

PE头的应用---插入代码到EXE或DLL文件中的更多相关文章

  1. C# .exe和.dll文件图标资源提取工具

    Windows 可执行文件(.exe)和动态库文件(.dll)图标资源提取工具 GitHub 功能 图标资源预览 图标资源导出(仅支持导出 PNG 格式) 代码 获取图标资源使用了 Win32 API ...

  2. 有关windows系统的EXE和DLL文件说法错误

    正确答案: B C   你的答案: C (错误) EXE和DLL文件都是PE文件 EXE不能有导出函数,DLL可以有导出函数 EXE有x86和x64之分,则DLL没有 EXE可以单独运行,DLL则不行 ...

  3. 使用ILmerge合并Exe、Dll文件的帮助类

    原文:使用ILmerge合并Exe.Dll文件的帮助类 using System; using System.Collections.Generic; using System.Text; using ...

  4. .net Reactor之exe、dll文件混淆

    .net Reactor之exe.dll文件混淆 .net Reactor的主要功能: 1.是对dll文件.exe文件进行反编译混淆 2.对dll进行内部加锁,限制其使用的固定机器.固定时间.部署次数 ...

  5. 通过AssemblyResolve事件打包合并exe和dll文件

    使用WPF开发的安装包,在创建快捷方式的时候,需要用到COM程序集Windows Script Host Object Model,引用COM程序集后,会在debug目录生成Interop.IWshR ...

  6. 怎样判断一个exe可执行程序(dll文件)是32位的还是64位的

    看到一个比较简单粗暴的方式,做个记录. 直接用记事本或者notepad++(文本编辑软件都可)打开exe文件(dll文件), 会有很多乱码,接下来只需要在第二段中找到PE两个字母,在其后的不远出会出现 ...

  7. 如何将一个Form中的代码拆分到多个文件中

    https://social.msdn.microsoft.com/Forums/en-US/64c77755-b0c1-4447-8ac9-b5a63a681b78/partial-class-fo ...

  8. 将exe和dll文件打包成单一的启动文件

    当我们用 VS 或其它编程工具生成了可执行exe要运行它必须要保证其目录下有一大堆dll库文件,看起来很不爽,用专业的安装程序生成软件又显得繁琐,下面这个方法教你如何快速把exe文件和dll文件打包成 ...

  9. Linux:使用awk命令获取文本的某一行,某一列;sed插入指定的内容到指定文件中

    awk相关用法: 1.打印文件的第一列(域)                 : awk '{print $1}' filename2.打印文件的前两列(域)                 : aw ...

随机推荐

  1. HDU 2685 I won't tell you this is about number theory

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2685 题意:求gcd(a^m - 1, a^n - 1) mod k 思路:gcd(a^m - 1, ...

  2. mysql学习(四)-字段类型

    mysql数据类型: 数值型: 整形:int 浮点型:float double decimal:定点型 日期: date  '2012-01-02' time '10:01:01' datetime ...

  3. Android BaseAdapter

    ListView显示与缓存机制:      只会加载当前屏幕所要显示的数据.显示完成就会被回收到Recycler中.       BaseAdapter 基本结构:      public int g ...

  4. Android studio 查看sha1

    高德地图开发申请KEY的时候需要开发者提供SHA1证书指纹数据,在eclipse很容易就找到了,但是Android Studio很久也没找到,只能使用在网上看到的方法了,在Android Studio ...

  5. SQL Server 恢复过程

    在恢复过程中.只会分析那些自最后一个检查点之后发生的更改,以确定是否需要重做还是撤销. 在最后一个检查点之前完成的操作都会精确的反应到数据文件中,恢复过程不需要做其它的事. 第一阶段: 分析. 这个阶 ...

  6. INFOQ几篇论文

    http://www.infoq.com/cn/articles/java-profiling-with-open-source http://www.infoq.com/cn/articles/Vi ...

  7. BadgeView使用介绍

    前段时间做的一个淘宝客的项目,需要在商品图片上添加价格标签,之前自己使用TextView和Cavas绘制的感觉效果一般,今天偶然在CSDN上发现BadgeView这个开源项目,在git下载下来之后,使 ...

  8. SQLServer2012 和 MariaDB 10.0.3 分页效率的对比

    1. 实验环境      R910服务器, 16G内存 SqlServer 2012   64bit MariaDB 10.0.3   64bit  (InnoDB) 2. 实验表情况 rtlBill ...

  9. [Leetcode][Python]30: Substring with Concatenation of All Words

    # -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 30: Substring with Concatenation of All ...

  10. Joseph(约瑟夫环)

    Joseph Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...