国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
淺談api hook技術(shù)
 

        APIHook一直是使大家感興趣的話題。屏幕取詞,內(nèi)碼轉(zhuǎn)化,屏幕翻譯,中文平臺(tái)等等都涉及到了此項(xiàng)技術(shù)。有很多文章涉及到了這項(xiàng)技術(shù),但都閃爍其詞不肯明明白白的公布。我僅在這里公布以下我用Delphi制作APIHook的一些心得。
       通常的APIHOOK有這樣幾種方法:
      1、自己寫一個(gè)動(dòng)態(tài)鏈接庫,里面定義自己寫的想取代系統(tǒng)的API。把這個(gè)動(dòng)態(tài)鏈接庫映射到2G以上的系統(tǒng)動(dòng)態(tài)鏈接庫所在空間,把系統(tǒng)動(dòng)態(tài)鏈接庫中的該API的指向修改指向自己的函數(shù)。這種方法的好處就是可以取代系統(tǒng)中運(yùn)行全部程序的該API。但他有個(gè)局限,就是只適用于Win9x。(原因是NT中動(dòng)態(tài)鏈接庫不是共享的,每個(gè)進(jìn)程都有自己的一份動(dòng)態(tài)鏈接庫在內(nèi)存中的映射)
      2、自己寫一個(gè)動(dòng)態(tài)鏈接庫,里面定義自己寫得象替代系統(tǒng)的API。把這個(gè)動(dòng)態(tài)鏈接庫映射到進(jìn)程的空間里。將該進(jìn)程對(duì)API的調(diào)用指向自己寫的動(dòng)態(tài)鏈接庫。這種方法的好處是可以選擇性的替代哪個(gè)進(jìn)程的API。而且適用于所有的Windows操作系統(tǒng)。
      這里我選用的是第二種方法。
      第二種方法需要先了解一點(diǎn)PE文件格式的知識(shí)。
       首先是一個(gè)實(shí)模式的的DOS文件頭,是為了保持和DOS的兼容。
       接著是一個(gè)DOS的代理模塊。你在純DOS先運(yùn)行Win32的可執(zhí)行文件,看看是不是也執(zhí)行了,只是顯示的的是一行信息大意是說該Windows程序不能在DOS實(shí)模式下運(yùn)行。
       然后才是真正意義上的Windows可執(zhí)行文件的文件頭。它的具體位置不是每次都固定的。是由文件偏移$3C決定的。我們要用到的就是它。
       如果我們在程序中調(diào)用了一個(gè)MessageBoxA函數(shù)那么它的實(shí)現(xiàn)過程是這樣的。他先調(diào)用在本進(jìn)程中的MessageBoxA函數(shù)然后才跳到動(dòng)態(tài)鏈接庫的MessageBoxA的入口點(diǎn)。即:
       call messageBoxA(0040106c)
       jmp dword ptr [_jmp_MessageBoxA@16(00425294)]
其中00425294的內(nèi)容存儲(chǔ)的就是就是MessageBoxA函數(shù)的入口地址。如果我們做一下手腳,那么......
      那就開始吧!
我們需要定義兩個(gè)結(jié)構(gòu)
type
   PImage_Import_Entry = ^Image_Import_Entry;
   Image_Import_Entry = record
      Characteristics: DWORD;
      TimeDateStamp: DWORD;
      MajorVersion: Word;
      MinorVersion: Word;
      Name: DWORD;
      LookupTable: DWORD;
   end;
type
   TImportCode = packed record
      JumpInstruction: Word; file: //定義跳轉(zhuǎn)指令jmp
      AddressOfPointerToFunction: ^Pointer; file: //定義要跳轉(zhuǎn)到的函數(shù)
   end;
   PImportCode = ^TImportCode;
然后是確定函數(shù)的地址。
function LocateFunctionAddress(Code: Pointer): Pointer;
var
   func: PImportCode;
begin
   Result := Code;
   if Code = nil then exit;
   try
      func := code;
      if (func.JumpInstruction = $25FF) then
      begin
         Result := func.AddressOfPointerToFunction^;
      end;
   except
      Result := nil;
   end;
end;
參數(shù)Code是函數(shù)在進(jìn)程中的指針,即那條Jmp XXX的指令。$25FF就是跳轉(zhuǎn)指令的機(jī)器碼。
再下一篇我會(huì)講如何替換下那個(gè)XXX的內(nèi)容,讓他跳到你想去的地方。

在這里我將要實(shí)現(xiàn)轉(zhuǎn)跳。有人說修改內(nèi)存內(nèi)容要進(jìn)入Ring 0 才可以??墒荳indows本身提供了一個(gè)寫內(nèi)存的指令WriteProcessMemory。有了這把利器,我們幾乎無所不能。如游戲的修改等在這里我們只談APIHOOK。
function RepointFunction(OldFunc, NewFunc: Pointer): Integer;
var
   IsDone: TList;
   function RepointAddrInModule(hModule: THandle; OldFunc, NewFunc: Pointer): Integer;
   var
      Dos: PImageDosHeader;
      NT: PImageNTHeaders;
      ImportDesc: PImage_Import_Entry;
      RVA: DWORD;
      Func: ^Pointer;
      DLL: string;
      f: Pointer;
      written: DWORD;
   begin
      Result := 0;
      Dos := Pointer(hModule);
      if IsDone.IndexOf(Dos) >= 0 then exit;
      IsDone.Add(Dos);

      OldFunc := LocateFunctionAddress(OldFunc);

      if IsBadReadPtr(Dos, SizeOf(TImageDosHeader)) then exit;
      if Dos.e_magic <> IMAGE_DOS_SIGNATURE then exit;
      NT := Pointer(Integer(Dos) + dos._lfanew);

      RVA := NT^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
         .VirtualAddress;

      if RVA = 0 then exit;
      ImportDesc := pointer(integer(Dos) + RVA);
      while (ImportDesc^.Name <> 0) do
      begin
         DLL := PChar(Integer(Dos) + ImportDesc^.Name);
         RepointAddrInModule(GetModuleHandle(PChar(DLL)), OldFunc, NewFunc);
         Func := Pointer(Integer(DOS) + ImportDesc.LookupTable);
         while Func^ <> nil do
         begin
            f := LocateFunctionAddress(Func^);
            if f = OldFunc then
            begin
               WriteProcessMemory(GetCurrentProcess, Func, @NewFunc, 4, written);
               if Written > 0 then Inc(Result);
            end;
            Inc(Func);
         end;
         Inc(ImportDesc);
      end;
   end;

begin
   IsDone := TList.Create;
   try
      Result := RepointAddrInModule(GetModuleHandle(nil), OldFunc, NewFunc);
   finally
      IsDone.Free;
   end;
end;
有了這兩個(gè)函數(shù)我們幾乎可以更改任何API函數(shù)。
我們可以先寫一個(gè)DLL文件。我這里以修改Text相關(guān)函數(shù)為例:
先定義幾個(gè)函數(shù):
type
   TTextOutA = function(DC: HDC; X, Y: Integer; Str: PAnsiChar; Count: Integer): BOOL; stdcall;
   TTextOutW = function(DC: HDC; X, Y: Integer; Str: PWideChar; Count: Integer): BOOL; stdcall;
   TTextOut = function(DC: HDC; X, Y: Integer; Str: PChar; Count: Integer): BOOL; stdcall;
   TDrawTextA = function(hDC: HDC; lpString: PAnsiChar; nCount: Integer; var lpRect: TRect; uFormat: UINT): Integer; stdcall;
   TDrawTextW = function(hDC: HDC; lpString: PWideChar; nCount: Integer; var lpRect: TRect; uFormat: UINT): Integer; stdcall;
   TDrawText = function(hDC: HDC; lpString: PChar; nCount: Integer; var lpRect: TRect; uFormat: UINT): Integer; stdcall;
var
   OldTextOutA: TTextOutA;
   OldTextOutW: TTextOutW;
   OldTextOut: TTextOut;
   OldDrawTextA: TDrawTextA;
   OldDrawTextW: TDrawTextW;
   OldDrawText: TDrawText;
......
function MyTextOutA(DC: HDC; X, Y: Integer; Str: PAnsiChar; Count: Integer): BOOL; stdcall;
begin
   OldTextOutA(DC, X, Y, ‘ABC‘, length(‘ABC‘));
end;

function MyTextOutW(DC: HDC; X, Y: Integer; Str: PWideChar; Count: Integer): BOOL; stdcall;
begin
   OldTextOutW(DC, X, Y, ‘ABC‘, length(‘ABC‘));
end;

function MyTextOut(DC: HDC; X, Y: Integer; Str: PChar; Count: Integer): BOOL; stdcall;
begin
   OldTextOut(DC, X, Y, ‘ABC‘, length(‘ABC‘));
end;

function MyDrawTextA(hDC: HDC; lpString: PAnsiChar; nCount: Integer; var lpRect: TRect; uFormat: UINT): Integer; stdcall;
begin
   OldDrawTextA(hDC, ‘ABC‘, length(‘ABC‘), lpRect, uFormat);
end;

function MyDrawTextW(hDC: HDC; lpString: PWideChar; nCount: Integer; var lpRect: TRect; uFormat: UINT): Integer; stdcall;
begin
   OldDrawTextW(hDC, ‘ABC‘, length(‘ABC‘), lpRect, uFormat);
end;

function MyDrawText(hDC: HDC; lpString: PChar; nCount: Integer; var lpRect: TRect; uFormat: UINT): Integer; stdcall;
begin
   OldDrawText(hDC, ‘ABC‘, length(‘ABC‘), lpRect, uFormat);
end;

調(diào)用時(shí)我們要把原來的函數(shù)地址保存下來:
   if @OldTextOutA = nil then
      @OldTextOutA := LocateFunctionAddress(@TextOutA);
   if @OldTextOutW = nil then
      @OldTextOutW := LocateFunctionAddress(@TextOutW);
   if @OldTextOut = nil then
      @OldTextOut := LocateFunctionAddress(@TextOut);
   if @OldDrawTextA = nil then
      @OldDrawTextA := LocateFunctionAddress(@DrawTextA);
   if @OldDrawTextW = nil then
      @OldDrawTextW := LocateFunctionAddress(@DrawTextW);
   if @OldDrawText = nil then
      @OldDrawText := LocateFunctionAddress(@DrawText);
然后很順其自然的用自己的函數(shù)替換掉原來的函數(shù)
   RepointFunction(@OldTextOutA, @MyTextOutA);
   RepointFunction(@OldTextOutW, @MyTextOutW);
   RepointFunction(@OldTextOut, @MyTextOut);
   RepointFunction(@OldDrawTextA, @MyDrawTextA);
   RepointFunction(@OldDrawTextW, @MyDrawTextW);
   RepointFunction(@OldDrawText, @MyDrawText);
        在結(jié)束時(shí)不要忘記恢復(fù)原來函數(shù)的入口,要不然你會(huì)死得很難看喲!好了我們在寫一個(gè)Demo程序。你會(huì)說怎么文字沒有變成ABC呀?是呀,你要刷新一下才行。最小化然后在最大化??纯醋兞藳]有。  
        要不然你就寫代碼刷新一下好了。至于去攔截其他進(jìn)程的API那就用SetWindowsHookEx寫一個(gè)其他的鉤子將DLL映射進(jìn)去就行了,我就不再浪費(fèi)口水了。
掌握了該方法你幾乎無所不能。你可以修改其它程序。你可以攔截Createwindow等窗口函數(shù)改變其他程序的窗口形狀、你還可以入侵其它的程序,你還可以......嘿嘿。干了壞事別招出我來就行了。
我還寫了個(gè)例子,請?jiān)贑SDN上下載。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Delphi下調(diào)用API Hook
“金山詞霸”技術(shù)delphi參考代碼
delphi攔截 網(wǎng)絡(luò)數(shù)據(jù)封包
vb調(diào)用C++寫的DLL
Delphi如何調(diào)用C++寫的DLL
C++回調(diào)函數(shù)(callback)的使用
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服