We don't display ads so we rely on your Bitcoin donations to 1KWEk9QaiJb2NwP5YFmR24LyUBa4JyuKqZ
Post date: Mar 16, 2010 3:52:13 PM
{
Unit: uAddImport
Author: steve10120
Description: Add imports to a PE file.
Website: ic0de.org
History: First try
Added multiple import support.
}
unit uAddImport;
//steve10120
interface
uses Windows;
type
TFuncArray = array of string;
TImports = packed record
szLibName: string;
Funcs: TFuncArray;
end;
procedure AddImport(szFilePath:string; Imports:TImports);
type
PImageImportDescriptor = ^TImageImportDescriptor;
TImageImportDescriptor = packed record
OriginalFirstThunk: DWORD;
TimeDateStamp: DWORD;
ForwarderChain: DWORD;
Name: DWORD;
FirstThunk: DWORD;
end;
type
PImportByName = ^TImportByName;
TImportByName = packed record
Name1: DWORD;
end;
type
TByteArray = array of Byte;
implementation
function FileToBytes(sPath:string; var bFile:TByteArray):Boolean;
var
hFile: THandle;
dSize: DWORD;
dRead: DWORD;
begin
Result := FALSE;
hFile := CreateFile(PChar(sPath), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if hFile <> 0 then
begin
dSize := GetFileSize(hFile, nil);
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
SetLength(bFile, dSize);
if ReadFile(hFile, bFile[0], dSize, dRead, nil) then
Result := TRUE;
CloseHandle(hFile);
end;
end;
procedure BytesToFile(bData:TByteArray; sPath:string);
var
hFile: THandle;
dWritten: DWORD;
begin
hFile := CreateFile(PChar(sPath), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if hFile <> 0 then
begin
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
WriteFile(hFile, bData[0],Length(bData), dWritten, nil);
CloseHandle(hFile);
end;
end;
function OffsetToRVA(dwOffset:DWORD; dwVA:DWORD; dwRaw:DWORD):DWORD;
begin
Result := dwOffset - dwRaw + dwVA;
end;
function RVAToOffset(dwRVA:DWORD; dwVA:DWORD; dwRaw:DWORD):DWORD;
begin
Result := dwRVA - dwVA + dwRaw;
end;
function Align(dwValue:DWORD; dwAlign:DWORD):DWORD;
begin
if dwAlign <> 0 then
begin
if dwValue mod dwAlign <> 0 then
begin
Result := (dwValue + dwAlign) - (dwValue mod dwAlign);
Exit;
end;
end;
Result := dwValue;
end;
procedure AddImport(szFilePath:string; Imports:TImports);
var
bFile: TByteArray;
IDH: PImageDosHeader;
INH: PImageNtHeaders;
ISH: PImageSectionHeader;
IID: PImageImportDescriptor;
IBN: array of TImportByName;
i: DWORD;
dwIATPos: DWORD;
dwPos: DWORD;
bBuff: TByteArray;
dwSize: DWORD;
begin
if FileToBytes(szFilePath, bFile) then
begin
IDH := @bFile[0];
if IDH.e_magic = IMAGE_DOS_SIGNATURE then
begin
INH := @bFile[IDH._lfanew];
if INH.Signature = IMAGE_NT_SIGNATURE then
begin
for i := 0 to INH.FileHeader.NumberOfSections - 1 do
begin
ISH := @bFile[IDH._lfanew + 248 + i * 40];
if (INH.OptionalHeader.DataDirectory[1].VirtualAddress >= ISH.VirtualAddress) and (INH.OptionalHeader.DataDirectory[1].VirtualAddress <= (ISH.VirtualAddress + ISH.Misc.VirtualSize)) then
begin
dwIATPos := RVAToOffset(INH.OptionalHeader.DataDirectory[1].VirtualAddress, ISH.VirtualAddress, ISH.PointerToRawData);
Break;
end;
end;
IID := @bFile[dwIATPos];
SetLength(bBuff, 20);
dwPos := 0;
repeat
CopyMemory(@bBuff[dwPos], IID, 20);
Inc(IID);
Inc(dwPos, 20);
SetLength(bBuff, dwPos + 20);
until IID.Name = 0;
dwPos := Length(bFile);
dwSize := Align(Length(bBuff) + 20, INH.OptionalHeader.FileAlignment);
SetLength(bFile, Length(bFile) + dwSize);
ISH := @bFile[IDH._lfanew + 248 + (INH.FileHeader.NumberOfSections - 1) * 40];
Imports.szLibName := Imports.szLibName + #0;
CopyMemory(@bFile[dwPos], @Imports.szLibName[1], Length(Imports.szLibName));
IID.Name := OffsetToRVA(dwPos, ISH.VirtualAddress, ISH.PointerToRawData);
Inc(dwPos, Length(Imports.szLibName));
SetLength(IBN, Length(Imports.Funcs));
for i := 0 to Length(Imports.Funcs) - 1 do
begin
Imports.Funcs[i] := #0#0 + Imports.Funcs[i] + #0;
CopyMemory(@bFile[dwPos], @Imports.Funcs[i][1], Length(Imports.Funcs[i]));
IBN[i].Name1 := OffsetToRVA(dwPos, ISH.VirtualAddress, ISH.PointerToRawData);
Inc(dwPos, Length(Imports.Funcs[i]));
end;
IID.FirstThunk := OffsetToRVA(dwPos + Length(bBuff) + 20, ISH.VirtualAddress, ISH.PointerToRawData);
CopyMemory(@bBuff[Length(bBuff) - 20], IID, 20);
SetLength(bBuff, Length(bBuff) + 20);
CopyMemory(@bFile[dwPos], @bBuff[0], Length(bBuff));
INH.OptionalHeader.DataDirectory[1].VirtualAddress := OffsetToRVA(dwPos, ISH.VirtualAddress, ISH.PointerToRawData);
INH.OptionalHeader.DataDirectory[1].Size := Length(bBuff);
Inc(dwPos, Length(bBuff));
for i := 0 to Length(IBN) - 1 do
begin
CopyMemory(@bFile[dwPos], @IBN[i], 4);
Inc(dwPos, 4);
end;
Inc(ISH.SizeOfRawData, dwSize);
Inc(ISH.Misc.VirtualSize, dwSize);
CopyMemory(@bFile[IDH._lfanew + 248 + (INH.FileHeader.NumberOfSections - 1) * 40], ISH, 40);
INH.OptionalHeader.SizeOfImage := ISH.VirtualAddress + ISH.Misc.VirtualSize;
CopyMemory(@bFile[IDH._lfanew], INH, 248);
BytesToFile(bFile, szFilePath);
end;
end;
end;
end;
end.
Usage:
var
Imports: TImports;
begin
SetLength(Imports.Funcs, 2);
Imports.szLibName := 'urlmon.dll';
Imports.Funcs[0] := 'URLDownloadToFileA';
Imports.Funcs[1] := 'URLDownloadToFileW';
AddImport('Hello.exe', Imports);
end.