This article does not describe how to use pure VB to implement hook APIs. If you want to learn more details, you must understand some VC and a little compilation knowledge, and refer to my other articles, if you are a loyal VB user, you can not understand the internal principles, because those are things that VC does (do not dislike to listen, I have no tendency to racial discrimination, because I don't know how to use VB to implement it, I won't use VB at all. I have studied it for a few days in this article, and there are very few Vb-related codes in this article, the VB-related code in this article was posted on csdn a few days ago.) You can directly use a standard DLL file provided by me and call several simple functions like calling a common API, in addition, you can implement your own Interception Function in your VB code. Okay. Let me explain it in detail.
First, assume that you want to know how to use the vb hook api. Otherwise, you should continue scrolling until you introduce how to use the paragraph. Secondly, if you haven't read my other articles about hook api under VC, you can check them out quickly, this is because I want to talk about the following content. If you have read these articles, the first article in the series is: HOOK API jump method.
In the series of articles, pay attention to the general functions, because this is the key to implementation in this article. Let's review the functions of the general function. We know that any API function we intercept will be included in our general functions, while general functions are of the type of no parameter and no return value. We use assembly to construct the function call stack and call the user's interception function without knowing the parameter type through stack operations. That is to say, if you want to intercept an API, you will tell me the name of the API you want to intercept and the replacement function that you want to process this API. When I intercept an API, it will call the replacement function that you told me to process this API. The problem to be solved now is that the replacement function of this processing API is in VB! After my unremitting efforts, I finally learned how to pass the function address in VB! (It is actually an addressof operator ). Now, all the conditions for the hook api to work are met. Let's get started.
To modify the code in "firewall principles and implementations", you only need to modify the initialization code. The original code is to obtain information about the API to be intercepted from a DLL file written by a VC, it is mainly to get the hookapiinfo structure through the gethookapiinfo function, and then convert the hookapiinfo structure to the apiinfo structure. In fact, the key point is how to obtain the apiinfo result.
Create an ActiveX dll project in VB. In this way, you create a COM component and the default project creates a class module for you. In this class module, you must add a method called gethookapiinfo. Its return value is an array of the apiinfo_vb type. The VB type is defined as follows:
Public type hookapiinfo_vb
Myapifuncaddr as long' our function address
Orgmodulename as string 'module name of the API to be intercepted
The name of the API to intercept.
Paramcount as long 'number of parameters of the API to be intercepted
End type
You also need to provide a method to obtain the function address, which is very simple, as follows:
Private function getaddr (byval address as long) as long
Getaddr = address
End Function
The gethookapiinfo method structure is roughly as follows:
Public Function gethookapiinfo ()
Dim param (1) as hookapiinfo_vb
Param (0). myapifuncaddr = getaddr (addressof message)
Param (0). orgapiname = "messageboxa"
Param (0). orgmodulename = "user32.dll"
Param (0). paramcount = 4
Gethookapiinfo = Param
End Function
Here we only want to intercept the messageboxa function. Of course, we also need to add a module and define the Interception Function and message. When the target process executes the function to intercept and messageboxa is used, the message method of VB code will be called. In the C ++ chooapi class initialization function, we will obtain the apiinfo_vb structure array. The C ++ structure corresponding to the apiinfo_vb structure of VB is the _ hookapiinfo_vb structure, which is defined as follows:
Typedef struct _ hookapiinfo_vb
{
// Our own function address
DWORD dwmyapifuncaddr;
// The Name Of The module where the API to be blocked is located
BSTR bstrorgmodulename;
// The Name Of The API to intercept
BSTR bstrorgapiname;
// Number of API parameters to intercept
Long paramcount;
} Hookapiinfo_vb;
To call the gethookapiinfo function in the VB code to obtain the hookapiinfo_vb structure, we write the chookapi initialization Code as follows:
Coinitialize (null );
CLSID = {0x2ed7f30b, 0x2135, 0x4de1, {0x99,0x22, 0xEE, 0xb7, 0x02, 0x1e, 0x8f, 0xb4 }};
Hresult hR = cogetclassobject (CLSID, clsctx_inproc_server, null, iid_iclassfactory, (void **) & m_pcf );
M_pcf-> createinstance (null, iid_idispatch, (void **) & m_pdsp );
Olechar * szgethookapiinfo [] = {L "gethookapiinfo "};
Dispid;
HR = m_pdsp-> getidsofnames (iid_null, szgethookapiinfo, 1, locale_system_default, & dispid );
Dispparams Params = {null, null, 0, 0 };
Variant vresult;
HR = m_pdsp-> invoke (dispid, iid_null, locale_system_default, dispatch_method, & Params, & vresult, null, null );
M_pdsp-> release ();
M_pcf-> release ();
Of course, error handling is omitted here. The above code calls the gethookapiinfo method through the idispatch interface of VB. Here we need the CLSID value of the COM component written by VB. How can we get this value? This value can be obtained through the configuration file, which is more universal. Now the hookapiinfo_vb structure array is in the vresult. Let's take it out and convert it to the apiinfo structure. The Code is as follows:
For (ulong I = 0; I <vresult. parray-> rgsabound-> celements; I ++)
{
Hookapiinfo_vb * PHAI = (hookapiinfo_vb *) vresult. parray-> pvdata;
If (PHAI = NULL)
Continue;
Char szorgmodulename [100];
Char szorgapiname [50];
If (! Widechartomultibyte (cp_acp, 0, PHAI-> bstrorgmodulename,-1, szorgmodulename, 99, null, null ))
Continue;
If (! Widechartomultibyte (cp_acp, 0, PHAI-> bstrorgapiname,-1, szorgapiname, 99, null, null ))
Continue;
Apiinfo * PAI = new apiinfo;
// Number of saved Parameters
PAI-> paramcount = PHAI-> paramcount;
// Set whether this API has been hook
PAI-> bishooked = false;
// Memory protection mark
PAI-> dwoldprotectflag = 0;
// Our function address
PAI-> lfmyapiaddr = (cmapifunc) PHAI-> dwmyapifuncaddr;
// Function address to intercept
Hmodule hmod = getmodulehandle (szorgmodulename );
If (hmod = NULL)
{
Delete Pai;
Continue;
}
PAI-> lforgapiaddr = (cmapifunc) getprocaddress (hmod, szorgapiname );
If (PAI-> lfmyapiaddr = NULL)
{
Delete Pai;
Continue;
}
Strcpy (PAI-> szorgapiname, szorgapiname );
M_vpapiinfo.push_back (PAI );
}
Here we have filled the m_vpapiinfo container, and other hook operations are similar to those written in II. Firewall principles and implementation (1.
Next I will talk about ii. Firewall principles and implementation (1) What we need to modify and pay attention to in order to comply with our VB code.
1. Call conventions
I encountered various pop-up windows when I started to implement this program. At that time, the scene was a strong one. Later, I realized that the function call convention in the original VB module was _ stdcall. That is to say, the stack is balanced by the function itself and no caller intervention is required, in my article II. Firewall principles and implementation (1), the Code of commonfunc is called back to call C-type functions, so there will be problems in calling VB functions, the solution is to delete the stack balancing code. The modified code is as follows:
Void chookapi: commonfunc (void)
{
DWORD dwlpfunc; // address of the replacement function _ stdcall
DWORD * pdwcall; // Save the return address in the stack before the call, that is, the address of call XXXX.
DWORD * pdwesp; // save ESP content
DWORD * pdwparam; // address of the first parameter
DWORD dwparamsize; // The size occupied by all parameters should be 4 * dwparamcount
DWORD dwrt; // Save the returned value
DWORD dwrtaddr; // address that our function really wants to return
Process_information * PPI; // Process Information
// Obtain the position of the first parameter in the stack
_ ASM
{
MoV eax, [EBP + 8]
MoV [dwrtaddr], eax
Lea eax, [EBP + 4] // address of call xxxx
MoV [pdwcall], eax
Lea eax, [EBP + 12] // address of the first parameter
MoV [pdwparam], eax
}
(* Pdwcall)-= 5;
Vector <apiinfo *>: iterator it;
Apiinfo * PAI = NULL;
For (IT = m_vpapiinfo.begin (); it! = M_vpapiinfo.end (); It ++)
{
Apiinfo * papiinfo = * it;
If (DWORD) papiinfo-> lforgapiaddr = * pdwcall)
{
Pai = * it;
Break;
}
}
If (PAI = NULL)
Return;
Byte * pbtapi = (byte *) PAI-> lforgapiaddr;
Dwparamsize = 4 * PAI-> paramcount;
Entercriticalsection (& PAI-> CS );
// Restore the modified 5 bytes
Memcpy (pbtapi, Pai-> orgapibytes, 5 );
PAI-> bishooked = false;
Dwlpfunc = (DWORD) PAI-> lfmyapiaddr;
// Construct parameters
_ ASM
{
Sub ESP, [dwparamsize]
MoV [pdwesp], ESP
}
Memcpy (pdwesp, pdwparam, dwparamsize );
// Commonfunc myapifunc = (commonfunc) PAI-> lfmyapiaddr;
// PAI-> lfmyapiaddr (); // call the function that replaces the API
_ ASM
{
Call dwlpfunc
// Save the returned value
MoV [dwrt], eax
}
// If it is CreateProcess, continue to hook it
PPI = (process_information *) pdwparam [9];
If (strcmpi (PAI-> szorgapiname, "createprocessa") = 0 | strcmpi (PAI-> szorgapiname, "createprocessw") = 0)
{
Injectdll (PPI-> dwprocessid, m_szdllpathname );
}
// Modify the value by 5 bytes.
Pbtapi [0] = callcode; // JMP
DWORD * pdwapi = (DWORD *) & (pbtapi [1]);
Pdwapi [0] = (DWORD) commonfunc-(DWORD) pbtapi-5; // address offset of my API
PAI-> bishooked = true;
Leavecriticalsection (& PAI-> CS );
// The operations to be returned are as follows:
_ ASM
{
// Add ESP, [dwparamsize] // clear the parameters in the stack allocated to call the replacement function
MoV edX, [dwrtaddr] // Save the return address
MoV eax, dwrt // set the return value
MoV ECx, [dwparamsize] // obtain the parameter size
// All the saved register values are displayed below (in reverse order of the inbound stack)
Pop EDI // restore EDI
Pop ESI // restore ESI
Pop EBX // restore EBX
// We have not changed the EBP value, so the EBP points to the oldebp position in the stack.
MoV ESP, EBP
Pop EBP // restore EBP
// Because there are still parameters and two return addresses left in the stack (the address we actually want to return and the 6th-byte address in the original API), we also clear the data from the stack.
Add ESP, 8 // clear two return addresses
Add ESP, ECx // clear parameters
// Because the program first extracts the return address from the stack when the RET return is called, we press the address to be actually returned into the stack.
Push edX
RET // return
}
}
2. about VB strings
I also thought about many methods to solve the string problem, but all of them failed. The main cause of this problem is that the VB strings are of the BSTR type, * *** A APIs are common ANSI strings. Because in my general functions, I do not know the parameter or the return value is a string. So I threw this problem to the VB user and asked you to solve it. For example, to intercept the messageboxa function, the VB interception function should be known as follows:
Public Function Message (byval h as long, byval MSG as long, byval title as long, byval ntype as long) as integer
Dim mymsg as string
Dim strlen as long
Mymsg = sysallocstring (MSG)
Msgbox mymsg, vbokonly, "liutao hooked"
End Function
That is, the second and third parameters, use two long variables to save the string pointer of the lpctstr type, and then use sysallocstring to construct BSTR and convert it to the string type of VB. Sysallocstring is named as follows:
Private declare function sysallocstring lib "oleaut32" (byval olechar as long) as string
At this point, we have solved all the problems of calling back the DLL written by VB in VC code, so my hook api will work normally.