如何保存原始函数的地址并在以后调用它?
How save the address of original function and call this later?
我正在尝试在 api 挂钩中调用原始函数,以防止 LdrLoadDll()
函数注入 dll,但每次我尝试加载不同的 dll 时,应用程序都会崩溃并且不可能调用原始函数。似乎我做错了什么时候会在挂钩之前保存 "original_function" 。
我正在 Windows 7 x64 上进行测试,在 32 位应用程序(代码如下)中注入 32 位 dll。
如何解决这个问题?
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
SysUtils;
type
NTSTATUS = Cardinal;
PUNICODE_STRING = ^UNICODE_STRING;
UNICODE_STRING = packed record
Length: Word;
MaximumLength: Word;
Buffer: PWideChar;
end;
const
STATUS_ACCESS_DENIED = NTSTATUS($C0000022);
var
Old_LdrLoadDll: function(szcwPath: PWideChar; dwFlags: DWORD;
pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
: NTSTATUS; stdcall;
function LdrLoadDll(szcwPath: PWideChar; dwFlags: DWORD;
pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
: NTSTATUS; stdcall;
begin
Result := Old_LdrLoadDll(szcwPath, dwFlags, pUniModuleName, pResultInstance);
end;
procedure PatchCode(Address: Pointer; const NewCode; Size: Integer);
var
OldProtect: DWORD;
begin
if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then
begin
Move(NewCode, Address^, Size);
FlushInstructionCache(GetCurrentProcess, Address, Size);
VirtualProtect(Address, Size, OldProtect, @OldProtect);
end;
end;
type
PInstruction = ^TInstruction;
TInstruction = packed record
Opcode: Byte;
Offset: Integer;
end;
procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
NewCode: TInstruction;
begin
NewCode.Opcode := $E9;
NewCode.Offset := NativeInt(NewAddress) - NativeInt(OldAddress) -
SizeOf(NewCode);
PatchCode(OldAddress, NewCode, SizeOf(NewCode));
end;
function NewLdrLoadDll(szcwPath: PWideChar; dwFlags: DWORD;
pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
: NTSTATUS; stdcall;
begin
if (pos('111', pUniModuleName.Buffer) > 0) or
(pos('222', pUniModuleName.Buffer) > 0) then
Result := STATUS_ACCESS_DENIED
else
Result := LdrLoadDll(szcwPath, dwFlags, pUniModuleName, pResultInstance);
end;
begin
@Old_LdrLoadDll := GetProcAddress(GetModuleHandle('ntdll.dll'), 'LdrLoadDll');
try
RedirectProcedure(GetProcAddress(GetModuleHandle('ntdll.dll'),
'LdrLoadDll'), @NewLdrLoadDll);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
我建议您不要使用自制的挂钩,为此获取一个现有的库。
Microsoft Detours 现在是免费和开源的。当它构建为 DLL 时,您可以将它与 Delphi.
一起使用
您将需要 C++ 编译器从源代码构建它,但是 Visual Studio 社区是免费的。
这是在遵循@GolezTrol 建议后制作的一个工作代码:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
SysUtils;
type
NTSTATUS = Cardinal;
PUNICODE_STRING = ^UNICODE_STRING;
UNICODE_STRING = packed record
Length: Word;
MaximumLength: Word;
Buffer: PWideChar;
end;
const
STATUS_ACCESS_DENIED = NTSTATUS($C0000022);
var
Old_LdrLoadDll: function(szcwPath: PWideChar; dwFlags: DWORD;
pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
: NTSTATUS; stdcall;
function LdrLoadDll(szcwPath: PWideChar; dwFlags: DWORD;
pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
: NTSTATUS; stdcall;
begin
Result := Old_LdrLoadDll(szcwPath, dwFlags, pUniModuleName, pResultInstance);
end;
type
PInstruction = ^TInstruction;
TInstruction = packed record
Opcode: Byte;
Offset: Integer;
end;
//======= Structure to store original function ========
type
TSaveOriginal = packed record
Addr: Pointer;
Bytes: array [0 .. SizeOf(TInstruction)] of Byte;
end;
PSaveOriginal = ^TSaveOriginal;
var
SaveOriginal: TSaveOriginal;
//====================================================
procedure PatchCode(Address: Pointer; const NewCode; Size: Integer;
SaveOriginal: PSaveOriginal);
var
OldProtect: DWORD;
begin
if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then
begin
//======== Saving original function =========
if Assigned(SaveOriginal) then
begin
SaveOriginal^.Addr := Address;
Move(Address^, SaveOriginal^.Bytes, Size);
end;
//===========================================
Move(NewCode, Address^, Size);
FlushInstructionCache(GetCurrentProcess, Address, Size);
VirtualProtect(Address, Size, OldProtect, @OldProtect);
end;
end;
procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
NewCode: TInstruction;
begin
NewCode.Opcode := $E9;
NewCode.Offset := NativeInt(NewAddress) - NativeInt(OldAddress) -
SizeOf(NewCode);
PatchCode(OldAddress, NewCode, SizeOf(NewCode), @SaveOriginal);
end;
procedure UndoRedirectProcedure(const SaveOriginal: TSaveOriginal);
var
OldProtect: Cardinal;
begin
if not VirtualProtect(SaveOriginal.Addr, SizeOf(TInstruction),
PAGE_EXECUTE_READWRITE, OldProtect) then
RaiseLastOSError;
Move(SaveOriginal.Bytes, SaveOriginal.Addr^, SizeOf(TInstruction));
if not VirtualProtect(SaveOriginal.Addr, SizeOf(TInstruction), OldProtect,
OldProtect) then
RaiseLastOSError;
end;
function NewLdrLoadDll(szcwPath: PWideChar; dwFlags: DWORD;
pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
: NTSTATUS; stdcall;
begin
if (pos('111', pUniModuleName.Buffer) > 0) or
(pos('222', pUniModuleName.Buffer) > 0) then
Result := STATUS_ACCESS_DENIED
else
begin
UndoRedirectProcedure(SaveOriginal); // Restore original function
@Old_LdrLoadDll := SaveOriginal.Addr;
Result := LdrLoadDll(szcwPath, dwFlags, pUniModuleName, pResultInstance); // Call original function
RedirectProcedure(GetProcAddress(GetModuleHandle('ntdll.dll'),
'LdrLoadDll'), @NewLdrLoadDll); // Hook again
end;
end;
begin
try
RedirectProcedure(GetProcAddress(GetModuleHandle('ntdll.dll'),
'LdrLoadDll'), @NewLdrLoadDll);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
我正在尝试在 api 挂钩中调用原始函数,以防止 LdrLoadDll()
函数注入 dll,但每次我尝试加载不同的 dll 时,应用程序都会崩溃并且不可能调用原始函数。似乎我做错了什么时候会在挂钩之前保存 "original_function" 。
我正在 Windows 7 x64 上进行测试,在 32 位应用程序(代码如下)中注入 32 位 dll。
如何解决这个问题?
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
SysUtils;
type
NTSTATUS = Cardinal;
PUNICODE_STRING = ^UNICODE_STRING;
UNICODE_STRING = packed record
Length: Word;
MaximumLength: Word;
Buffer: PWideChar;
end;
const
STATUS_ACCESS_DENIED = NTSTATUS($C0000022);
var
Old_LdrLoadDll: function(szcwPath: PWideChar; dwFlags: DWORD;
pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
: NTSTATUS; stdcall;
function LdrLoadDll(szcwPath: PWideChar; dwFlags: DWORD;
pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
: NTSTATUS; stdcall;
begin
Result := Old_LdrLoadDll(szcwPath, dwFlags, pUniModuleName, pResultInstance);
end;
procedure PatchCode(Address: Pointer; const NewCode; Size: Integer);
var
OldProtect: DWORD;
begin
if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then
begin
Move(NewCode, Address^, Size);
FlushInstructionCache(GetCurrentProcess, Address, Size);
VirtualProtect(Address, Size, OldProtect, @OldProtect);
end;
end;
type
PInstruction = ^TInstruction;
TInstruction = packed record
Opcode: Byte;
Offset: Integer;
end;
procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
NewCode: TInstruction;
begin
NewCode.Opcode := $E9;
NewCode.Offset := NativeInt(NewAddress) - NativeInt(OldAddress) -
SizeOf(NewCode);
PatchCode(OldAddress, NewCode, SizeOf(NewCode));
end;
function NewLdrLoadDll(szcwPath: PWideChar; dwFlags: DWORD;
pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
: NTSTATUS; stdcall;
begin
if (pos('111', pUniModuleName.Buffer) > 0) or
(pos('222', pUniModuleName.Buffer) > 0) then
Result := STATUS_ACCESS_DENIED
else
Result := LdrLoadDll(szcwPath, dwFlags, pUniModuleName, pResultInstance);
end;
begin
@Old_LdrLoadDll := GetProcAddress(GetModuleHandle('ntdll.dll'), 'LdrLoadDll');
try
RedirectProcedure(GetProcAddress(GetModuleHandle('ntdll.dll'),
'LdrLoadDll'), @NewLdrLoadDll);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
我建议您不要使用自制的挂钩,为此获取一个现有的库。
Microsoft Detours 现在是免费和开源的。当它构建为 DLL 时,您可以将它与 Delphi.
一起使用您将需要 C++ 编译器从源代码构建它,但是 Visual Studio 社区是免费的。
这是在遵循@GolezTrol 建议后制作的一个工作代码:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
SysUtils;
type
NTSTATUS = Cardinal;
PUNICODE_STRING = ^UNICODE_STRING;
UNICODE_STRING = packed record
Length: Word;
MaximumLength: Word;
Buffer: PWideChar;
end;
const
STATUS_ACCESS_DENIED = NTSTATUS($C0000022);
var
Old_LdrLoadDll: function(szcwPath: PWideChar; dwFlags: DWORD;
pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
: NTSTATUS; stdcall;
function LdrLoadDll(szcwPath: PWideChar; dwFlags: DWORD;
pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
: NTSTATUS; stdcall;
begin
Result := Old_LdrLoadDll(szcwPath, dwFlags, pUniModuleName, pResultInstance);
end;
type
PInstruction = ^TInstruction;
TInstruction = packed record
Opcode: Byte;
Offset: Integer;
end;
//======= Structure to store original function ========
type
TSaveOriginal = packed record
Addr: Pointer;
Bytes: array [0 .. SizeOf(TInstruction)] of Byte;
end;
PSaveOriginal = ^TSaveOriginal;
var
SaveOriginal: TSaveOriginal;
//====================================================
procedure PatchCode(Address: Pointer; const NewCode; Size: Integer;
SaveOriginal: PSaveOriginal);
var
OldProtect: DWORD;
begin
if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then
begin
//======== Saving original function =========
if Assigned(SaveOriginal) then
begin
SaveOriginal^.Addr := Address;
Move(Address^, SaveOriginal^.Bytes, Size);
end;
//===========================================
Move(NewCode, Address^, Size);
FlushInstructionCache(GetCurrentProcess, Address, Size);
VirtualProtect(Address, Size, OldProtect, @OldProtect);
end;
end;
procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
NewCode: TInstruction;
begin
NewCode.Opcode := $E9;
NewCode.Offset := NativeInt(NewAddress) - NativeInt(OldAddress) -
SizeOf(NewCode);
PatchCode(OldAddress, NewCode, SizeOf(NewCode), @SaveOriginal);
end;
procedure UndoRedirectProcedure(const SaveOriginal: TSaveOriginal);
var
OldProtect: Cardinal;
begin
if not VirtualProtect(SaveOriginal.Addr, SizeOf(TInstruction),
PAGE_EXECUTE_READWRITE, OldProtect) then
RaiseLastOSError;
Move(SaveOriginal.Bytes, SaveOriginal.Addr^, SizeOf(TInstruction));
if not VirtualProtect(SaveOriginal.Addr, SizeOf(TInstruction), OldProtect,
OldProtect) then
RaiseLastOSError;
end;
function NewLdrLoadDll(szcwPath: PWideChar; dwFlags: DWORD;
pUniModuleName: PUNICODE_STRING; pResultInstance: PPointer)
: NTSTATUS; stdcall;
begin
if (pos('111', pUniModuleName.Buffer) > 0) or
(pos('222', pUniModuleName.Buffer) > 0) then
Result := STATUS_ACCESS_DENIED
else
begin
UndoRedirectProcedure(SaveOriginal); // Restore original function
@Old_LdrLoadDll := SaveOriginal.Addr;
Result := LdrLoadDll(szcwPath, dwFlags, pUniModuleName, pResultInstance); // Call original function
RedirectProcedure(GetProcAddress(GetModuleHandle('ntdll.dll'),
'LdrLoadDll'), @NewLdrLoadDll); // Hook again
end;
end;
begin
try
RedirectProcedure(GetProcAddress(GetModuleHandle('ntdll.dll'),
'LdrLoadDll'), @NewLdrLoadDll);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.