8-sentence code to realize message boxa of Delphi 10.3 inline hook under win10

Keywords: PHP Delphi Windows calculator

First of all, I'd like to thank myy of Delphi's learning and communication group for debugging for 6 hours yesterday, which was finally completed. Let's record it so as not to let some fans detour. I can't understand the information of a certain degree. I think it's better to dig a hole and fill it up by myself.
Two problems should be paid attention to under win10:

1.OpenProcess is unable to get the handle of the process. Generally, this problem calls this function in Dll and returns to 5 with GetLastError, which means that no access is allowed. DLL has not tried the following three methods for the time being.
Solution:
1.EXE is run by administrator and added by OD.
2. Use the lifting function to upgrade to DEBUG permission
This problem does not occur when Delphi itself IDE runs EXE

2. The fifth parameter of writeprocessmemory, ipnumberofbytewriten, is not of Cardinal type but of native type. The reference here is wrong. If the Cardinal type is written, it will prompt that the actual parameter and the formal parameter are inconsistent. It may also be that native type is a branch of Cardinal type. I will not explore here. Anyway, Delphi's reference goes into winapi.windows and looks at the source code, and its reference is different, pit.

The code is as follows: will explain sentence by sentence

 1 function lens(x,y:Integer):Integer;               //Declare a function lens,lens Function is calculation JMP Distance from api The distance from function jump to new function
 2 begin
 3   Result:=x-y-5;                  // X=New function address, Y=api Function address, because Jmp(16 Binary system E9 1 byte)+distance(4 bytes),Actually, the jump is from api address+5 Start to jump. If you don't subtract 5, you will actually jump to the address of the new function.+5
 4 end;                                //Example: if the new function address=00000006,api address=00000000,So the take-off position is actually 00000006.-00000000-5,If you don't subtract 5, you will jump to 00000006+5 Location
 5  
 6 function MyMessages(hWnd: Cardinal; lpText, lpCaption: PAnsiChar; uType: Cardinal):Integer; stdcall;   //Declare a and MessageBoxA Functions of the same type, named MyMessages,Be sure to use stdcall Contract, otherwise an error will be called
 7 var
 8   text: PAnsiChar;               //Define a variable as text,The type is the same as the type of the formal parameter PAnsiChar,Easy to operate formal parameters
 9 begin                              //Notice to declare a function, whether the function has code or not, you should use begin end Put it all together, otherwise IDE Infinite prompt error
10   text := lpText;                 //order ipText Value=text,In this way, I can get MessageBoxA The contents of the parameters of
11   ShowMessage('The title of the information box I get is: ' + text);    //Call at this time ShowMessage,Debug output MessageBoxA Of IpText Parameter value
12  
13 end;
14  
15 procedure TForm1.Button2Click(Sender: TObject);      //Here is a button event. I added two buttons, one is to call the original information box, the other is to Hook Button, this is Hook Button
16   var
17     hp: Integer;                                                                 //Define a variable as HP,Used to save process handle
18     apiaddr: Integer;                                                        //Define a variable as apiaddr,Used to save the acquired api Address, obtained api The address of is in decimal, but we don't need to convert to OD For convenient viewing, it can be called manually. calc Calculator for conversion or ctrl+F5 Add monitoring
19     read: array[1..5] of Byte;                                            //Define an element sequence number as 1-5 Array named read,Type is byte Type, which means to save 5 bytes for saving api The 5 bytes of the function, because we need to modify these 5 bytes to jump to the new function, then it will be easy to recover Hook
20     rd: NativeUInt;                                                          //Define a variable as rd,Type is NativeUInt,This variable is a function that stores several bytes of the actual operation. For example, I read or write five bytes. If the operation is successful, the value here is 5, otherwise it is 0. It is explained above that the type must be NativeUInt,
21     jmps: Integer;                                                           //Define a variable as Jmps,It's here to save Jmp Machine code of( E9)The decimal system of, because we operate in the decimal system, it is said that there is no need to convert to OD 16 binary system
22     tiaoshi,tiaoshi1: Integer;                                          //This is used to debug the output content. It's convenient for me to find problems. It's OK not to.
23   begin
24     hp := OpenProcess(PROCESS_ALL_ACCESS, False, GetCurrentProcessId);              //OpenProcess Function, if the operation succeeds, then hp The third parameter uses the GetCurrentProcessId,Represents the process that gets its own process ID,If you want to operate other processes, you need to fill in the processes of the processes to be operated. ID,But be careful DLL Form EXE Unable to operate
25     apiaddr := Integer(GetProcAddress(LoadLibrary('user32.dll'), 'MessageBoxA'));   //Use here LoadLibrary Obtain user32.dll The address of the module can also be called the handle of the module. GetProcessAddress Obtain MessageBoxA Of api Address, GetProcessAddress The return is Pointer Type, so use Integer Convert to integer, i.e. decimal
26     ReadProcessMemory(hp, Pointer(apiaddr), Pointer(@read), 5, rd);       //use ReadProcessMemory read api First 5 bytes of function,Save in read In the array, ReadProcessMemory(process handle:Cradinal type,Read address: pointer Type, save read data: pointer type(plus@Represents the address of the stored data, which is called the address),Size of read data: Cradinal Type, actual size: NativeUInt type)
27     jmps := 233;                                                                                                          //JMP Machine code of( E9)Decimal system
28     WriteProcessMemory(hp, Pointer(apiaddr), Pointer(@jmps), 1, rd);                    //take E9 First byte written to first address
29     tiaoshi:=Integer(@MyMessages) ;                                                                       //Here I debug the output to see if I can get the address of the new function.@Indicates the actual address of the new function. readprocessmemory The third parameter of is the same meaning.
30     tiaoshi1 := lens(Integer(@MyMessages), apiaddr);                                             //Here I debug the output viewing distance (taking up 4 bytes), i.e. JMP The machine code of the next four bytes is actually converted to hexadecimal in the form of. Suppose the value of debugging output is 01020304, then OD It needs to be reversed, that is, 04030201, in this form.
31     WriteProcessMemory(hp, Pointer(apiaddr + 1), Pointer(@tiaoshi1), 4, rd);       //The distance is written here because the api The address of is the first byte we wrote E9,So we need to write 4 bytes from the second byte, so apiaddr+1
32     CloseHandle(hp) ;                                                                                              //Here we close the process handle we opened. Although I don't know why, it seems to be closing.
33  
34   end;
35  
36 procedure TForm1.Button1Click(Sender: TObject);                                      //Here's the first button I said, calling the original MessageBoxA
37 begin
38   MessageBoxA(0, 'I am the title.', 'I am content.', 0)
39 end;

Posted by jfs0479 on Fri, 01 Nov 2019 21:26:36 -0700