Windows core programming 3 (dllmain, setwindowshookex, and structured exception handling)

Source: Internet
Author: User
Tags finally block readfile

This article from: http://hi.baidu.com/huguosheng/blog/item/1f925438eb826cf1b311c7f0.html

1 DLL entry point function dllmain
Bool apientry dllmain (handle hmodule,
DWORD ul_reason_for_call,
Lpvoid lpreserved
)
{

Switch (ul_reason_for_call)
{
Case dll_process_attach:
Case dll_thread_attach:
Case dll_thread_detach:
Case dll_process_detach:
Break;
}
Return true;
}

Dll_process_attach: When the DLL is first mapped to the address space of the process, the system calls dllmain and passes the dll_process_attach value for ul_reason_for_call. In this case, the DLL can execute any process-related initialization. Instance. If a DLL is injected into a new process and some tasks are automatically executed, the code is written after case dll_process_attach.
Dll_process_detach: After the DLL is detached from the address space of the process, the system calls dllmain and passes the dll_process_detach value for ul_reason_for_call. For example, if you call freelibrary, call dllmain to complete the dll_process_detach notification before returning it from freelibrary.
Dll_thread_attach: when creating a thread in a process, the system needs to check all DLL file images mapped to the address space of the process, and call each dllmain function with dll_thread_attach, in this case, you can tell the DLL to execute the initialization of the thread. Note: The system does not call any dllmain with the dll_thread_attach value for the main thread of the process. The DLL in the address space of the process to be started for the first time receives the dll_process_attach notification rather than the dll_thread_attach notification.
Dll_thread_detach: When the thread is terminated, the exitthread is called to cancel the thread. In this case, the dllmain of the DLL with dll_thread_detach is called first, and the thread is being revoked.

 

2 DLL Injection

2.1 inject DLL through Windows Hook message
First look at the following code:
Hhook = setwindowshookex (wh_getmessage, getmsgproc, hinstdll, 0 );
Wh_getmessage: indicates the hook type, which is a message hook.
Getmsgproc: the address of the function called by the system when the window is preparing to process the message ??????????
Hinstdll: RVA in the address space of the process to which the DLL is mapped.
0: hook all gui processes.

Let's see what happened:
1. a thread of process B is preparing to send a message to a window.
2. Check whether the wh_getmessage hook is installed in this thread.
3. Check whether the DLL containing getmsgproc is mapped to the address space of process B.
4. If it is not mapped, It is forcibly mapped to the address space of B to implement DLL injection.
5. The system calls the getmsgproc function of process B (ing ).

2.2 use a remote process to insert a DLL
Idea: Create a remote thread in the desired process and call loadlibrary to load the required DLL. We only need to call
Createremotethread (hremoteprocess, null, 0, loadlibrarya, "C: // mylib. dll", 0, null. But no.
Error 1: loadlibrarya cannot be passed in directly as a parameter, because this causes remote threads to execute some inexplicable things and may cause access violations.
Solution: pfnaddr = (pthread_start_routine) getprocaddress (getmodulehandle (text ("Kernel32"), "loadlibrarya"); then pass in pfnaddr.
Error 2: You cannot directly input "C: // mylib. dll" because the buffer is in this process and not in a remote thread. You should apply for a space (virtualallocex) in the remote thread and write "C: // mylib. dll" into this space (writeprocessmemory ).

Sample Code:

# Include <windows. h>
# Include <stdio. h>
Void main ()
{
Lpctstr dllpath = "D: // print. dll"; // The DLL to be injected. The content is to write a log file to the hard disk.
DWORD sizedllpath = 0, dwwritten = 0;
Handle premotethread, hremoteprocess;
Pthread_start_routine pfnaddr;
Dword pid;
Void * pfileremote;
Bool Fok;
Sizedllpath = lstrlena (dllpath) + 1;
Printf ("Size: % d", sizedllpath );
Hwnd hwinpro =: findwindow ("progman", null); // obtain the Explorer window

If (! Hwinpro)
Printf ("exploere not started ");
Else
{
: Getwindowthreadprocessid (hwinpro, & pid); // obtain the explorer handle
Hremoteprocess =: OpenProcess (process_all_access | process_vm_write, false, pid );
Pfileremote =: virtualallocex (hremoteprocess, null, sizedllpath, mem_commit | mem_reserve, page_execute_readwrite );
// Allocate space in the explorer process
If (pfileremote)
{
Printf ("allocated successfully/N ");
}
Fok =: writeprocessmemory (hremoteprocess, pfileremote, (lpvoid) dllpath, sizedllpath, & dwwritten );
Printf ("actual number of bytes written: % d/N", dwwritten );
Printf ("number of bytes to be written: % d/N", sizedllpath );
If (FOK = false)
{
Printf ("writeprocessmemory error/N ");
Return;
}
Pfnaddr = (pthread_start_routine) getprocaddress (getmodulehandle (text ("Kernel32"), "loadlibrarya ");
Premotethread =: createremotethread (hremoteprocess, null, 0, pfnaddr, pfileremote, 0, null );
If (premotethread = NULL)
Return;
Else
Printf ("success! /N ");
}
}

Structured exception handling (seh)
Structured exception handling includes two parts: End handling and exception handling.

4. End Processing
4.1 form
_ Try
{
// Protected part
}
_ Finally
{
// End Processing
}

Regardless of how the try part exits (call return, break, continue, Goto, etc.), the finally part will always be executed before exiting. If the try part does not have return, break, and continue, the process of the program automatically enters the finally part after the try part is executed (note that this is different from Exception Handling ).
4.2 analyze a program
To better understand the end processing, see the following procedure.
DWORD funcadoodledoo ()
{
DWORD dwtemp = 0;
While (dwtemp <10)
{
_ Try {
If (dwtemp = 2)
Continue;
If (dwtemp = 3)
Break;
}

_ Finally {
Dwtemp ++;
}
Dwtemp ++;
}
Dwtemp + = 10;
Return (dwtemp );
}

When dwtemp enters while, it enters finally in sequence, dwtemp changes to 1, then runs dwtemp ++, and changes to 2. Then it enters the starting part of the loop again and encounters the continue command, this will change the program flow to the Finally block, and the dwtemp ++ becomes 3. At this time, the loop starts. Note that dwtemp ++ outside the Finally block is not executed. Enter the try block again. In the case of the break command, enter the Finally block again, change dwtemp to 4, exit while, and run dwtemp + = 10. Therefore, 14 is returned.
4.3 terminate the application of the processing program
You can end the processing program to simplify programming, but note the following:Avoid using return, break, continue, and goto in the try block as much as possible, because this will generate a lot of code for the Compilation Program to process the process changes.
First look at a program
Bool fun1 ()
{
Handle hfile = invalid_handle_value;
Pvoid pvbuf = NULL;
DWORD dwnumbytesread;
Bool Fok;
Hfile = createfile ("somedata. Bat", generic_read, file_1__read, null, open_existing, 0, null );
If (hfile = invalid_handle_value)
Return false;
Pvbuf = virtualalloc (null, 1024, mem_coomit, page_readwrite );
If (pvbuf = NULL)
{
Closehandle (hfile );
Return false;
}

Fok = readfile (hfile, pvbuf, 1024, & dwnumbytesread, null );
If (! Fok | dwnumbytesread = 0)
{
Virtualfree (pvbuf, mem_release | mem_decommit );
Closehandle (hfile );
Return false;
}

// Do some calculation on the data
.
.
.
.

Virtualfree (pvbuf, mem_release | mem_decommit );
Closehandle (hfile );
Return true;

}

One disadvantage of this program is to clean up the code virtualfree, And the closehandle appears repeatedly, so that the program readability is reduced. Improve fun2.
Bool fun2 ()
{
Handle hfile = invalid_handle_value;
Pvoid pvbuf = NULL;
DWORD dwnumbytesread;
Bool Fok;
_ Try
{
Hfile = createfile ("somedata. Bat", generic_read, file_1__read, null, open_existing, 0, null );
If (hfile = invalid_handle_value)
Return false;
Pvbuf = virtualalloc (null, 1024, mem_coomit, page_readwrite );
If (pvbuf = NULL)
{
Return false;
}
Fok = readfile (hfile, pvbuf, 1024, & dwnumbytesread, null );
If (! Fok | dwnumbytesread = 0)
{
Return false;
}
}

// Do some calculation on the data
.
.
.
.
_ Finally
{

If (pvbuf! = NULL)
Virtualfree (pvbuf, mem_release | mem_decommit );
If (hfile! = Invalid_handle_value)
Closehandle (hfile );
}
Return true;

}
The code readability of the fun2 program is greatly improved, but return appears in the try block, which reduces the program efficiency. Fun3 uses _ leave to solve this problem well.
Bool fun3 ()
{
Handle hfile = invalid_handle_value;
Pvoid pvbuf = NULL;
DWORD dwnumbytesread;
Bool Fok;
Bool functionok = false;
_ Try
{
Hfile = createfile ("somedata. Bat", generic_read, file_1__read, null, open_existing, 0, null );
If (hfile = invalid_handle_value)
_ Leave;
Pvbuf = virtualalloc (null, 1024, mem_coomit, page_readwrite );
If (pvbuf = NULL)
{
_ Leave;
}
Fok = readfile (hfile, pvbuf, 1024, & dwnumbytesread, null );
If (! Fok | dwnumbytesread = 0)
{
_ Leave
}
}

Functionok = true;
// Do some calculation on the data
.
.
.
.
_ Finally
{

If (pvbuf! = NULL)
Virtualfree (pvbuf, mem_release | mem_decommit );
If (hfile! = Invalid_handle_value)
Closehandle (hfile );
}
Return functionok;

}
Fun2 achieves the ideal effect. You only need to add the variable functionok for control.
4. Summary
The benefits of end processing are as follows:
(1) Simplified error handling because all cleanup tasks are in one location and are ensured to be executed.
(2) improved readability
(3) properly used, you can write robust code with little system overhead.

 

5. Exception Handling
The CPU exception is caused by hardware exceptions (except for 0 exceptions, illegal memory access, etc.). The operating system and applications can also cause exceptions by themselves, which are called software exceptions.
5.1 form
_ Try
{
// Protected part
}
_ Expect T (exception filter)
{
// Exception Handling
}
Note: If the program runs normally, it does not enter blocks of blocks, which is different from finally.
5.2 exception filter
The filter parameter in _ Except (exception filter) is an exception filter. It can take three values:
Prediction_execute_handler
Prediction_continue_search
Prediction_continue_execution
(1) prediction_execute_handler
The value tells the system: "I recognize an exception. That is, I feel that this exception may occur at some time. I have written code to handle it. Now I want to execute this code ".
An example.
Char * strcpy (char * strdestionation, char * strsource)
If an Invalid Address is passed, the process ends. To make the program more robust, you can:
Char * robuststrcpy
{
_ Try
{
Strcpy (strdestionation, strsource)
}
_ Handler T (exception_execute_handler)
{
// Nothing to do here
}
Return strdestionation;
}
Let's look at another example.
Pbyte robustmemdup (pbyte pbsrc, size_t CB)
{
Pbyte pbdup = NULL;
_ Try
{
Pbdup = (pbyte) mallo (CB );
Memcpy (pbdup, pbsrc, CB );
}
_ Limit t
{
Free (pbdup );
Pbdup = NULL;
}
Return pbdup;
}
However, when a function fails, the allocated space is released and the caller is notified of the returned value.
(2) prediction_continue_execution
When the code generates an exception and the filter value is prediction_continue_execution, the system jumps back to the command that generates the exception and then executes it again. Therefore, if we do know which command generates any exception, we can fix it in blocks T, and then the system automatically goes back to execute the command with the exception, which has been corrected, the program can be executed normally. If you make good use of this function, it will produce amazing results. The example of the workbook below shows its clever application.
(3) prediction_continue_search
This value tells the system to find the first try block that matches the try t block and call the exception handling code of this try block.
5.3 one application instance-workbooks
If a spreadsheet program (such as Excel) allocates space when the program starts to execute, it will waste a lot of memory (because the workbook is usually very large, with a value for each grid, 1024*1024 will waste 1024*1024 * sizeof (INT) memory ). The solution is: first use virtualalloc (.., mem_reserve ,..) A large enough space is reserved in the process virtual space (reserve) without committing, so physical memory is not consumed. When you access a grid, virtualalloc (..., mem_commit,...) submits the memory of the grid. When a table is accessed but the memory is not submitted, the exception_access_violation exception will occur, and the value of the filter in the response T is set
Prediction_continue_execution. In the memory T block, physical memory is submitted for the memory to be accessed, that is, virtualalloc (.., mem_commit ,..), then re-execute the access code and the program runs normally if the physical memory has been allocated. The following program uses the idea of Windows core programming. Many examples on the Internet are used for implementation, and improvements are made to form code with low memory consumption and high efficiency.
// Virtualmatrix. h header file
# Include <windows. h>

Class virtualmatrix
{
Public:
Virtualmatrix (INT nrows, int ncols );
~ Virtualmatrix ();
Void setelement (int I, Int J, int value );
Int getelement (int I, Int J );
Long expfilter (DWORD dwexceptioncode, int I, Int J );
Protected:
Int ncols;
Int nrows;
Lpvoid m_pdata;
};

// CPP File

# Include <stdio. h>
# Include <windows. h>
# Include "virtualmatrix. H"

Virtualmatrix: virtualmatrix (INT nrows, int ncols ):
M_pdata (null ),
Ncols (0 ),
Nrows (0)
{
This-> ncols = ncols;
This-> nrows = nrows;

M_pdata = virtualalloc (null, nrows * ncols * sizeof (INT), mem_reserve, page_readwrite );

If (m_pdata = NULL)
{
MessageBox (null, text ("reserve failed"), text ("virtual matrix"), mb_ OK );
Return;
}

}

Virtualmatrix ::~ Virtualmatrix (void)
{
If (m_pdata! = NULL)
Virtualfree (m_pdata, 0, mem_release );
}

Void virtualmatrix: setelement (int I, Int J, int value)
{

If (I <0 | I> = nrows)
Return;

If (j <0 | j> = nrows)
Return;

Int * P = (int *) (m_pdata );

_ Try
{

* (P + I * ncols + J) = value;
}
_ Partition T (expfilter (getexceptioncode (), I, j ))
{

}
}

Long virtualmatrix: expfilter (DWORD dwexceptioncode, int I, Int J)
{

If (dwexceptioncode = exception_access_violation)
{
Virtualalloc (lpvoid (long) m_pdata + sizeof (INT) * (I * ncols + J), 10, mem_commit, page_readwrite );
Return exception_continue_execution;
}
Return exception_execute_handler;

}

Int virtualmatrix: getelement (int I, Int J)
{
If (I <0 | I> = nrows)
Return-1;

If (j <0 | j> = nrows)
Return-1;

_ Try
{
Int * P = (int *) (m_pdata );
Int val = * (p + I * ncols + J );

Return val;
}
_ Handler T (exception_execute_handler)
{
Return-1;
}
}

Void main ()
{
Virtualmatrix A (100,100 );
A. setelement (10, 10, 3 );
Printf ("% d", A. getelement (10, 10 ));
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.