|
The Concept
Often, applications need to be monitored. Say, you need to know how an
application is performing and need to keep a track on the resource usage. This
is quite possible if you are the author of the application or have control over
the source tree. What if the application is a third-party application? How can
you plan to monitor a complete black box? This article will target this area and
show you various ways in which this can be achieved. Even though the APIs used
in this article are documented in the Microsoft developer network (MSDN), you
won’t find a correct code snippet that shows you how to use them. And when you
read the documentation, you will yourself notice that it is quite complicated to
understand what has been written, forget about knowing how to use it! That’s why
I would like to say that whatever appears in the form of program code from now
on is all “undocumented” stuff. Like all undocumented code, this code is not
supported by the vendor and can change across versions.
The need
Before we even get started with understanding how to achieve the above, first
let us try and understand properly why one would require to do this, or, what
the “business benefit” would be. Even when I learned this technique, I was
working on a project that required me to monitor a particular set of APIs.
Although my scope was the entire system and monitoring each and every
application running, we will limit the scope of this article to monitoring just
one running application. Here are a few reasons why one would require doing
so:
- To log how the application is using a particular API. Now, this API could
also be your written function exposed by some custom COM component or library
dll. In a normal case, you will have to write the entire logging code inside
your dll. But with the API monitoring system, you can actually keep this logging
code generic and keep the monitoring specific to a running process.
- To change the behaviour of a particular API. Say you need to disable all
calls to a particular API. For example, user32.dll has an exported API
called
OpenFile, in order for you to disable a particular
application from using this API, you can override the OpenFile API
and write your own code (in case of disabling it, returning a failure value to
the caller). In this way, two things are highlighted, first, you can disable any
such API from any dll, and second, you can override the default behaviour of a
particular API and provide your own functionality.
The method of injecting code
Before we start of with understanding how to ‘inject’ code into a running
process, let us try and understand how applications work and how process memory
is organized. If this explanation gets too complicated, you can skip this part
and jump to the next section, ‘Writing the code’.
|
Import Table |
|
Internal Shared Memory |
|
Process Stack and Heap |
|
Export Table |
The above table gives a brief idea of how memory is allocated for any running
process in the Windows environment
Every process has sections in memory as seen in the diagram. When the process
starts, the global/shared data is loaded in the ‘Internal Shared Memory’ area.
It has been called ‘Internal’ because the data is global within the process but
not outside the process boundary. After this, the ‘Import Table’ and the ‘Export
Table’ are populated for this process. This information comes from the binary of
the process. Basically, the Import Table and the Export Table have the following
meaning:
Import Table
The Import Table lists all the dlls that the process will be using. From now
on, I will refer to dlls as “Modules”. It not only lists all the modules that
the process will use, but also pointers to functions. Keep this point in mind,
because we will be digging into this “Import Table” and changing the function
pointer to our function. Although the mechanism to do so sounds pretty simple
and straightforward, when you take a look at the code you will notice that it is
in fact not the case.
Export Table
The Export Table lists all the functions and the respective function pointers
that the running process will export. This is true if the process itself is a
dynamic link library.
Process Stack and Heap
These are locations that are used by the process dynamically. It is on the
stack that all function pointer tables and the respective variables required for
an entering function are stored.
The method that we will use to inject a particular code will run in the
following manner. Later, I will show you the respective code for the steps given
below:
- Develop a dll that will contain an exported function for the API, which you
require to monitor/override.
- Get a process id to a running process, which you need to modify.
- Open the process with respect to the process id using the
OpenProcess
API.
- Create a remote thread inside the running process to control the
LoadLibrary functionality of the running process.
- Execute this thread to ensure that the running process loads your dll into
its memory.
- Once your dll is loaded, and when the dll is attaching, get a pointer to the
import list inside the running process. This part is a bit tricky and will
require an understanding of how to iterate an Import Table list. To make life
easier, there are helper APIs available, which allow you to do this. This will
be explained in detail when explaining the code.
- Now after getting a pointer to the import function and a pointer to the
function itself, replace this pointer with a pointer to your function from the
dll.
After following the above steps, you will observe that any call to the
particular API will result in your function being called. In this way you can
monitor or override any API from any Module, provided that you know the name of
the Module.
A little clarity
Now that I have explained the steps involved, let’s go ahead and write the
code to achieve this. Before we write the code, we need to make the following
things very clear:
- This code ‘injection’ system will only work in the context of the currently
logged-in user. This clearly means that it is not possible to monitor an
application running under a different user context. This also means that you
cannot monitor or inject code into any application over a network and running
under a different user context.
- This system uses the
OpenProcess API with the
OPEN_ALL_ACCESS bit, which means that when you open the process,
you need to be the administrator of the machine or the creator of the process.
Also, you cannot open a process that has been created with a completely
different security descriptor. There is a way to handle this situation but it
might not work in all circumstances. There is something called “opening a
process with debug privileges”, read up on it in MSDN.
So, what are the pieces that we need to code? For API Monitoring consider the
following pieces of code:
- Shared Module - This is the dll that will export our function for the
corresponding API.
- Injector Application - This is the executable, or the utility that we
will write for code injection. This application basically accepts a process id
of the application we need to monitor and injects our shared module inside the
process space of that application.
- [Optional] - A device driver for new process creation/destruction
notificationThis is an Optional component, which I will explain but won’t
provide the source code. This is a device driver, which compiles with Microsoft
Windows DDK using Microsoft Visual C++ 6.0 Compiler. This driver basically fires
an event whenever a process has been created or destroyed. This driver is
important if you write a system-level injection code and need to know when a
process is created or destroyed. I wrote a device driver for this (kernel-mode)
because I couldn’t find an alternative for this in user-mode. Not even using
Hooks!
We will now plunge right into the Shared Module. This is a Windows Dynamic
Link Library, a very simple DLL that contains the overridden code as well as the
actual injection code. Why do we need the Injector Application if this DLL is
doing the injection part? We need the application for the simple reason that
DLLs can’t run by themselves. Another reason is that the injector application is
the one that will create memory, load the DLL, etc, inside the remote processes
space.
Now, let us see how to write such a DLL in MS VC++ 6.0: Just follow the
following steps; they are so simple that even if you have never used a VC++ IDE,
you can still create the DLL and write the corresponding code very easily:
- Start VC++ IDE. Select the Project template (from the Projects Tab) as
“Win32 Dynamic-Link Library.” DO NOT touch any other settings or checkboxes.
Enter the Project Name as “SharedModule”.
- Now, select the Project type as “A simple DLL project”.
- Now, the wizard will create the files for you and inject the basic code.
Open the file view from the Workspace View. If workspace view is not visible,
press ALT+0.
- From the file view, double-click on the SharedModule.cpp file. This
file will be visible under the “Source Files” tree.
- Add the code from SharedModule.cpp below the #include “stdafx.h”
line. There will be a point-by-point explanation of the code after we have
finished all the steps.
Now compile the application, it should successfully compile and generate the
DLL. If it fails, please feel free to send me a dump of the error log. Please
send it to Parag_pp@yahoo.com.
I will now explain the above code and we can then move ahead to writing the
code for the injector application.
Let us try and understand the code now. It’s assumed that you are a C/C++
developer. If you are not, then you can simply skip this section. Apart from the
standard stdio and stdlib, you will see that imghelp has been included—you
require this header file for the “helper APIs” that we have used. In order to
locate the module handle of our own DLL, we need to store the module handle
passed to our DllMain entry point. This is stored in the g_hModule
variable. You would have guessed by now that we are hooking the
CopyFileW function of the user32.dll library. In order to
call the original function after our work is done, we need to store the function
pointer of the original function. This is stored in the
g_OriginalCopyFileW variable.
Next, as we are using function pointers, we need to have a typedef that
contains the exact prototype declaration of the function as it exists in the
dll. The prototype of CopyFileW is MyCopyFileW_t. Just
below the prototype, you will see our function, which will be called after the
hooking has been done. If you see the function body, you will notice that the
function does not do anything at the moment. It simply calls the original
function, which is pointed by the g_OriginalCopyFileW pointer. It
is at this place that you can write your implementation code and may or may not
call the original function. In this way, you can override the default behaviour
of the CopyFileW library function.
I am sure you must be wondering why there is a ‘W’ at the end of the
CopyFile API always. This is because CopyFileW is the
Unicode implementation of the CopyFile function. There is also an ANSI version
of the CopyFile API, called CopyFileA. If you are or
have been a Visual Basic developer you might have been using an A at the end of
the API call while declaring the API using “Declare…. Alias….” etc. But now I
guess you know what the A at the end exactly means.
Let’s move on. Now comes the most important function that actually does the
hooking. This function is called SetHook. SetHook accepts four parameters. Here
are the four parameters and their significance:
hModuleOfCaller - This is the module handle of
the caller who is making the call to this API. Now, say there is a process
called “A” that is making a call to the CopyFile API. But this actual
implementation of the API call may or may not be in the process itself. It could
also reside inside a dll, which the process A refers to.
- When we iterate through all such loaded modules (dlls) for a particular
process, we have to make sure that all these modules/processes call our function
instead of the original library’s function. This parameter is hence the module
handle of one such loaded module.
LibraryName - This is the textual name of the
library. If the original function belongs to user32.dll, this parameter will
contain “user32.dll”.
OldFunctionPointer - This is the pointer to the
original function from the base library. Hence, if we are hooking the
CopyFile function of user32.dll, this parameter will
contain the pointer to the original function from user32.dll. This can
be obtained by using the GetProcAddress API.
NewFunctionPointer - This is the pointer to our
function.
Digging into SetHook
Now let us try and understand the SetHook function in detail. As
mentioned earlier, we need to iterate through a list of import descriptors and
change the function pointers to point to our function. This is exactly what the
SetHook function does. Let us understand how it does this. In order
to understand this quickly and clearly, consider dividing its tasks into the
following list:
- Get the address of the module’s import section. This is done using the
ImageDirectoryEntryToData helper API. Please read up on this API in
MSDN for further information. This is a very powerful and interesting
function.
- Loop through all descriptors and find the import descriptor containing
references to functions called.
- Once we get an address to the module’s import section we iterate through the
various entries and compare the library name passed to the function.
- Get pointer to caller’s Import Address Table (IAT). Once the library is
located, get the pointer to the Import Address Table that will actually contain
the various function pointers.
- Iterate through the import list, locate the function we want to hook and
replace the original function pointer to our function.
Now iterate through the IAT to locate our function. This function pointer
will be exactly the same as the one obtained by calling a
GetProcAddress. Once located, replace the old function pointer to
point to our function.
SetHook and multiple modules
Now that we have understood how to hook inside a loaded module using the
SetHook function, let us understand where to apply this knowledge.
It is quite possible that a particular process had loaded multiple modules at a
time. In order to apply a process-wise hook in an efficient manner, we need to
set a hook into each and every module loaded by the process. This is exactly
what the EnumAndSetHooks function does. Let us now try and
understand how this function works.
The following simple steps explain how EnumAndSetHook works:
- Loads the original library and gets an address to the original function.
- Depending on the parameter passed, it decides whether we need to
Hook
the function or to restore (Unhook) the function. This is
decided by the UnHook flag passed to this function.
- It then calls the
EnumProcessModules API from
PSAPI.DLL. This API gets a list of all the loaded modules for a
process. As the dll is loaded and run inside the hooked process,
GetCurrentProcess returns us the handle to the currently running
process.
- After getting a list of modules inside
hMods, we iterate
through the list and pass on every module handle to a subsequent call of
SetHook.
The DllMain
DllMain is the entry point to our dll. It does the
following:
- If the operation requested is of type “
DLL_PROCESS_ATTACH”,
store the original Module handle and call EnumAndSetHooks with
UnHook as FALSE indicating that we are hooking this
API. EnumAndSetHooks returns a pointer to the original function; we
will need this when unhooking from the API.
- If the operation requested is of type “
DLL_PROCESS_DETACH”,
restore the original function pointer by calling EnumAndSetHooks
with the UnHook set to TRUE.
We will now move on to understanding the Injector Application.
Now that we have sharedmodule.dll ready and have understood the code, let’s
move on to the "action application": the Injector Application. Here’s where all
the "remote" magic is taken care of. The Injector Application is the application
to which is passed the process id of the application we want to monitor. As
explained earlier, this application will open the process and load our DLL into
the process space. Here is the code to do that. The Injector Application is an
EXE file, so please follow the steps shown below to create one such EXE file. We
will create the EXE in VC++ as we created a DLL in VC++. The steps are very
simple. Please DO NOT modify any of the checkboxes or settings when following
the steps given below:
- Start VC++ IDE. Select the Project template (from the Projects Tab) as
"Win32 Console Application". Please remember not to tamper with any other
settings or checkboxes. Enter the Project Name as "Injector".
- Now, select the Project type as ‘A "Hello, World!" application.’
- Now, the wizard will create the files for you and inject the basic code.
Open the file view from the Workspace View. If workspace view is not visible,
press ALT+0.
- From the file view, double click on the Injector.cpp file. This file will be
visible under the "Source Files" tree.
- Add the code from Injector.cpp, just below the
#include
"stdafx.h" line.
Please compile sharedmodule.dll and Injector.exe. Now go to the command
prompt and run Injector.exe. Pass the process id of the application you
wish to monitor. This process id has to be passed to injector.exe at the command
prompt. Say, the process id of Explorer.exe is 1676, then you need to
run Injector.exe as follows:
C:\work\vc6\injector\injector.exe 1676
After running, your application will list out all the modules loaded by
Explorer.exe. It will then hook into Explorer.exe and wait for you
to press a key, after which it will unhook from Explorer.exe.
If you have any problems compiling Injector.exe, please send an e-mail
to parag_pp@yahoo.com.
Let us now understand what happens in the code.
The working
The Injector Application works in the following steps:
- Get the process id of the application from the command line (argv[1]).
- Call the
DoHook function with the UnHook parameter
set to false.
- Enumerate all the modules for that particular process, and during the
process store the handle of our "sharedmodule.dll" module.
- Call
DoHook with UnHook set to true
and module handle set to the stored module handle.
So, as you would have understood so far, the heart of the application lies
inside two main functions DoHook &
EnumModules.
DoHook–the process hooker
This function is called with three parameters:
pid – the Process id of the process which we are
going to hook/monitor.
UnHook – Boolean flag indicating whether we are
going to Hook or UnHook the process.
hFreeModule – Handle to the module which will
host our Remote Thread. This is neglected when hooking into the
process.
DoHook itself works in the following steps:
- Open the process with all possible access (
PROCESS_ALL_ACCESS)
with the OpenProcess API.
- Allocate memory into the remote process using the
VirtualAllocEx
API. We will require this memory to store the path to our module. When
our thread is called, this path will be used by the remote process to load the
module.
- Copy the path to the module into the memory we allocated inside the remote
process. The API used to do this is WriteProcessMemory.
- Now, if the operation is a hooking operation (which means UnHook is false),
get an address to the
FreeLibrary function from
Kernel32.dll, or if it is the other way around, then get an address to
the LoadLibraryA function from Kernel32.dll.
- If the operation is a hooking operation, call
LoadLibraryA with
a path to the module to be loaded. This is the magic call, which actually loads
our DLL into the remote processes address space! The moment our DLL is loaded,
the respective DllMain code is called from sharedmodule and things
start rolling! If the operation is an Un-hooking operation, FreeLibrary
is called with handle to our module. This forces a
DLL_PROCESS_DETACH being called.
- In both cases, whether hooking or un-hooking, we have to wait for
LoadLibraryA or FreeLibrary to finish. This is
achieved with a WaitForSingleObject API call.
- After completion, free the memory allocated inside the remote process. This
is achieved by the
VirtualFreeEx API.
- Now, close the respective handles, freeing the memory. So, as you must have
understood, it is this function which actually opens the remote process and
pushes in a thread into that process. Then our module is loaded by calling the
subsequent thread and the action begins.
In order to free or un-hook the application from our module, it is important
that we store the handle to our module once it’s loaded into the remote process.
To achieve this, we have the EnumModules function, explained next.
EnumModules
This is a very simple function and works in the following steps:
- Open the process, whose process id (pid) is passed to this function. This is
achieved by calling
OpenProcess API with
PROCESS_ALL_ACCESS.
- As we are going to call API from a library called PSAPI.dll, it
happens at times that the appropriate header file is missing. Considering that,
let’s load PSAPI.dll in order to be able to call the function from this
module.
- The two functions we are going to call from PSAPI.dll are:
EnumProcessModules – This function enumerates all a
modules for a particular process and stores their handles in a one-dimensional
array. GetModuleFileNameEx – This function gets the
path to the loaded module.
- Now, call
EnumProcessModules using the handle to the opened
process.
- Iterate through all the loaded modules and make subsequent calls to
GetModuleFileNameEx.
- During iteration, compare the retrieved module to our module path.
- If found, free this module and return the handle to the module, to the
caller.
You have to understand that we will require this function only when we are
unloading our DLL and require the module handle to our DLL.
That’s it! See how simple that was? With respect to all the APIs provided
throughout the articles, try hunting for them in MSDN. When found, forget about
implementing them, even understanding how they work would look difficult. We
hope this exercise provides a fairly good understanding of how all these APIs
are used. You can go ahead and modify the overridden MyCopyFileA
function to do whatever you wish! In this way, all subsequent calls to
MyCopyFileA from within the remote application will call your
code!!!
You might remember that we had mentioned something about a device driver.
Well, here’s a short introduction to that: All applications running on the
Windows operating system work in two modes—user mode and kernel mode. As far as
we know, there is no way of knowing when a process was created or deleted in
user mode. Although you can know which window was created or destroyed by
setting the system-wide CBT (Computer-Based Training) Hook, you still can’t know
which process was created or destroyed in user mode. To be notified of this,
Windows OS provides a kernel mode API called
PsSetCreateProcessNotifyRoutine. Using this, you can be notified of
a creation/deletion of a process. Now, you must be thinking how can a kernel
mode application talk to a user mode application? Well, it’s simple: by setting
a kernel mode event and acknowledging the same in user mode! Send an e-mail to
the aforementioned addresses if you are interested in obtaining the source code
demonstrating this.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 61 (Total in Forum: 61) (Refresh) | FirstPrevNext |
|
|
 |
|
|
Hi, This second post is without code.
I am new to C++ but familiar with vb.net Using Microsoft VisualStudio 2005 Standard Ed with Visual C++ 2005. Downloaded the source code for both Injector.exe SharedModule.dll I am now able to get them both to link/compile.
I believe injector.exe is working correctly but I suspect that SharedModule isn't.
How can I easily test these progs.
What process should I target? What dll in that process? What function in the dll should be targeted?
I would like a simple test like doing a hook in Notepad.exe with the keyboard or something similar. I don't really know enough about Windows functions, so I don't know which dll/function to target.
Can anyone help?
I also have many questions about the C++ code for these programs that I would like to ask.
Thanks. Thanks for any help.
Thanks PeterRod
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi, I am new to C++ but familiar with vb.net Using Microsoft VisualStudio 2005 Standard Ed with Visual C++ 2005. Downloaded the source code for both Injector.exe SharedModule.dll I am now able to get them both to link/compile.
I believe injector.exe is working correctly but I suspect that SharedModule isn't.
How can I easily test these progs.
What process should I target? What dll in that process? What function in the dll should be targeted?
I would like a simple test like doing a hook in Notepad.exe with the keyboard or something similar. I don't really know enough about Windows functions, so I don't know which dll/function to target.
Can anyone help?
I also have many questions about the C++ code for these programs that I would like to ask.
Thanks. Thanks for any help.
Thanks PeterRod
Following is my source code for injector.cpp SharedModule.cpp The many comments are to assist my understanding of the code.
// SharedModule.cpp : Defines the entry point for the DLL application. //
#include "stdafx.h" #include <stdio.h> #include <imagehlp.h> #include <stdlib.h> #include <conio.h>
//=================================================================== // // TargetProcess = Process as defined by its PID in Injector.exe command // // TargetDLL = the dll that is targeted for hooking. // In this example "kernel32.dll" // // TargetFunction = the function that will be detoured. // The target function is contained in TargetDLL.("kernel32.dll") // In this case the target function is "CopyFileW" //===================================================================
HANDLE g_hModule = INVALID_HANDLE_VALUE; PROC Ptr_TargetFunction;
//-------------- PROTOTYPES -------------------------------- // the prototype must have the identical number of args and data types as // the original Microsoft dll function that is targeted. // // the following definition is for the "CopyFileW" function in kernel32.dll
typedef BOOL WINAPI PrototypeOfTargetFunction ( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists );
//--------------- Detour Functions (Trampolines) --------------- // the args and data types of DetourFunction must also be identical to protoype
BOOL WINAPI DetourFunction(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists) { BOOL ReturnValue; PrototypeOfTargetFunction* fn = (PrototypeOfTargetFunction*)Ptr_TargetFunction; // call the original Microsoft targeted dll function ReturnValue = (*fn)(lpExistingFileName, lpNewFileName, bFailIfExists);
//-------------- Place code to modify/collect data here --------------
//--------------------------------------------------------------------- return ReturnValue; // pass the result back to original funcn }
//====================================================================
void SetHook(HMODULE hModuleOfCaller, LPSTR LibraryName, PROC OldFunctionPointer, PROC NewFunctionPointer) { if(hModuleOfCaller == g_hModule) return; if(hModuleOfCaller == 0) return;
ULONG ulSize;
// Get the address of the module’s import section
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData ( hModuleOfCaller, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize );
// Does this module have an import section ? if (pImportDesc == NULL) return;
// Loop through all descriptors and find the // import descriptor containing references to callee’s functions while (pImportDesc->Name) { PSTR pszModName = (PSTR)((PBYTE) hModuleOfCaller + pImportDesc->Name); if (_stricmp(pszModName, LibraryName) == 0) break; // Found
pImportDesc++; } // while
if (pImportDesc->Name == 0) return;
//Get caller’s IAT PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)( (PBYTE) hModuleOfCaller + pImportDesc->FirstThunk );
PROC pfnCurrent = OldFunctionPointer;
// Replace current function address with new one while (pThunk->u1.Function) { // Get the address of the function address PROC* ppfn = (PROC*) &pThunk->u1.Function; // Is this the function we’re looking for? BOOL bFound = (*ppfn == pfnCurrent);
if (bFound) { MEMORY_BASIC_INFORMATION mbi; ::VirtualQuery(ppfn, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
// In order to provide writable access to this part of the // memory we need to change the memory protection
if (FALSE == ::VirtualProtect(mbi.BaseAddress,mbi.RegionSize,PAGE_READWRITE,&mbi.Protect)) return;
*ppfn = *NewFunctionPointer;
BOOL bResult = TRUE;
// Restore the protection back DWORD dwOldProtect;
::VirtualProtect(mbi.BaseAddress,mbi.RegionSize,mbi.Protect,&dwOldProtect); break; } // if
pThunk++;
} // while }
//----------------------------------------------------------------------- //----------------------------------------------------------------------
PROC EnumAndSetHooks(LPSTR TargetDLL, LPSTR TargetFunction, PROC NewFunctionPointer, bool UnHook, PROC Custom) { HMODULE hMods[1024]; DWORD cbNeeded; unsigned int i; typedef BOOL (WINAPI * PFNENUMPROCESSMODULES) ( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );
HMODULE hBaseLib = LoadLibraryA(TargetDLL);
PROC hBaseProc;
if(UnHook) hBaseProc = (PROC) Custom; else hBaseProc = GetProcAddress(hBaseLib, TargetFunction);
PFNENUMPROCESSMODULES m_pfnEnumProcessModules; HMODULE m_hModPSAPI = ::LoadLibraryA("PSAPI.DLL");
m_pfnEnumProcessModules = (PFNENUMPROCESSMODULES)::GetProcAddress(m_hModPSAPI, "EnumProcessModules");
HANDLE hProcess = ::GetCurrentProcess();
if( m_pfnEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) { for ( i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ ) { SetHook(hMods[i], TargetDLL, hBaseProc, NewFunctionPointer); } }
return hBaseProc; }
// ------------------------------------------------------------------ // ------------------------------------------------------------------
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { // this line has never printed on the console ???? printf("\n Inside DllMain of Shared Module \n");
switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: g_hModule = hModule; // handle to this module Ptr_TargetFunction = EnumAndSetHooks("KERNEL32.DLL", "CopyFileW", (PROC) DetourFunction, false, 0); break;
case DLL_PROCESS_DETACH:
EnumAndSetHooks("KERNEL32.DLL", "CopyFileW", (PROC) GetProcAddress(LoadLibraryA("KERNEL32"),"CopyFileW"), true, (PROC) DetourFunction); break;
} return TRUE; }
====================================================================== ====================================================================== ====================================================================== ======================================================================
// Injector.cpp : Defines the entry point for the console application. //
#include "stdafx.h" #include <windows.h> #include <stdlib.h> #include <conio.h>
// ====================================================================== // =======================================================================
// ============= define Private variables ============================= // szLibFile is a one dimensional char Array[] of size MAX_PATH=259 // it contains the full path to SharedModule.dll // SharedModule.dll is our code for placing hooks into // the TargetFunction contained in TargetDLL
char szLibFile[MAX_PATH] = "C:\\Documents and Settings\\ROGER\\My Documents\\Visual Studio 2005\\Projects\\SharedModule\\Release\\sharedmodule.dll";
// ====================================================================== // ======================================================================
int DoHook(int pid, bool UnHook, HMODULE hFreeModule) { BOOL bResult;
// get handle of TargetProcess HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (hProcess == NULL) {printf("\nInvalid Process ID!!"); return 0;}
size_t cch = 1 + strlen(szLibFile);
// call Windows "VirtualAllocEx" function // allocate cch bytes of virtual memory in the TargetProcess // pszLibFileRemote is the pointer to the allocated memory. LPVOID pszLibFileRemote; pszLibFileRemote = ::VirtualAllocEx(hProcess, NULL, cch, MEM_COMMIT, PAGE_READWRITE);
if (pszLibFileRemote == NULL) { printf("\nMemory allocation in TargetProcess failed"); return 0; }
// call Windows "WriteProcessMemory" function // write the full pathname of 'SharedModule' into the allocated // memory area of TargetProcess. bResult = ::WriteProcessMemory(hProcess, (PVOID)pszLibFileRemote, (PVOID)szLibFile, cch, NULL);
if (!bResult) { printf("\nMemory Write in TargetProcess failed"); return 0; }
// Hooking is acheived by loading 'SharedModule' on a new thread // to be created in TargrtProcess. // Loading is done with LoadLibraryA. // TargetProcess is remote to our current process ('Injector.exe') // Therefore we need a function pointer to LoadLibraryA // TheFunction pointer must be of Data Type LPTHREAD_START_ROUTINE // to be consistent with the args in CreateRemoteThread. // In the case of Unhook we execute a FreeLibrary call on the remote thread
// define variable pfnThreadRtn to hold the function pointer // which will be the start address in the newly created thread in TargetProcess LPTHREAD_START_ROUTINE pfnThreadRtn = NULL;
// the reference here to kernel32.dll is permanent. // because "FreeLibrary" and "LoadLibraryA" are contained in kernel32.dll HMODULE hKern = ::GetModuleHandleA("kernel32");
if(UnHook) pfnThreadRtn = (LPTHREAD_START_ROUTINE)::GetProcAddress(hKern, "FreeLibrary"); else pfnThreadRtn = (LPTHREAD_START_ROUTINE)::GetProcAddress(hKern, "LoadLibraryA");
if (pfnThreadRtn == NULL) { printf("\nGetProcAddress Failed"); return 0; } HANDLE hThread; if(UnHook) // Create a remote thread on TargetProcess and execute a FreeLibrary call // with argument being the handle of 'SharedModule' // which is now loaded in TargetProcess. // this call transfers control to DllMain in 'SharedModule' // with ul_reason_for_call set to DLL_PROCESS_DETACH // and then removes 'SharedModule' from the TargetProcess
hThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, (HMODULE)hFreeModule, 0, NULL);
else // Create a remote thread on TargetProcess and execute a LoadLibraryA call // with argument being the pathname of 'SharedModule'. // this magic call injects 'SharedModule' into the TargetProcess // and transfers control to DllMain in 'SharedModule' // with ul_reason_for_call set to DLL_PROCESS_ATTACH hThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, (LPVOID)pszLibFileRemote, 0, NULL);
if (hThread == NULL) { printf("\nCreateRemoteThread in TargetProcess failed"); return 0; }
// wait for the remote thread to complete its operation ::WaitForSingleObject(hThread, INFINITE);
if (pszLibFileRemote != NULL) ::VirtualFreeEx(hProcess, (PVOID)pszLibFileRemote, 0, MEM_RELEASE);
if (hThread != NULL) ::CloseHandle(hThread);
if (hProcess != NULL) ::CloseHandle(hProcess);
return 1; }
// ==================================================================== // ==================================================================== // // Presently this function lists out all modules that are loaded in the TargetProcess // This function returns the handle of('SharedModule') to the calling prog. // The final version will remove all printing. //
HMODULE EnumModules(int pid) { HMODULE hMods[1024]; DWORD cbNeeded; bool bResult; DWORD dResult; dResult=0;
unsigned int i; int j , kk; kk=0; j=0;
// get handle of TargetProcess HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (hProcess == NULL) {printf("\nInvalid Process ID!!"); return 0;}
// This function uses the "EnumProcessModules" and "GetModuleFileNameExA" // functions which are contained in "psapi.dll"
// get handle of "C:\WINDOWS\system32\psapi.dll" HMODULE m_hModPSAPI = ::LoadLibraryA("PSAPI.DLL");
// define the Function Prototypes typedef BOOL (WINAPI * PFNENUMPROCESSMODULES) ( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );
typedef DWORD (WINAPI * PFNGETMODULEFILENAMEEXA) ( HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
// define our variables to hold the function pointers PFNENUMPROCESSMODULES m_pfnEnumProcessModules; PFNGETMODULEFILENAMEEXA m_pfnGetModuleFileNameExA;
// get the function pointer to "EnumProcessModules" in 'psapi.dll' m_pfnEnumProcessModules = (PFNENUMPROCESSMODULES)::GetProcAddress(m_hModPSAPI, "EnumProcessModules");
// get the function pointer to "GetModuleFileNameExA" in 'psapi.dll' m_pfnGetModuleFileNameExA = (PFNGETMODULEFILENAMEEXA)::GetProcAddress(m_hModPSAPI, "GetModuleFileNameExA");
// call the "EnumProcessModules" function // get handles of all loaded modules into hMods[] bResult = m_pfnEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded);
if( bResult ) { j = cbNeeded/sizeof(HMODULE)-1;
for ( i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ ) { char szModName[MAX_PATH]; // call the "GetModuleFileNameExA" function // Get the full pathname of each module. dResult = m_pfnGetModuleFileNameExA( hProcess, hMods[i], szModName, sizeof(szModName));
if ( dResult != 0 ) { // Print the module name and handle value.
printf("\t%d of %d %s (0x%08X)\n",i,j, szModName, hMods[i] );
if(strcmp(szModName, szLibFile) == 0) { kk=i; } } } }
// return the handle of 'SharedModule' to the caller, if it was found if (kk != 0) { ::FreeLibrary(m_hModPSAPI); ::CloseHandle(hProcess); return hMods[kk]; }
if (hProcess != NULL) ::CloseHandle(hProcess); return 0; }
// ====================================================================== // ======================================================================
int main(int argc, char* argv[]) { int pid = atol(argv[1]); //int pid=1464; HMODULE hModule;
int my_a = 0;
printf("\n"," ");
my_a = DoHook(pid, false, 0); // attach to PID
printf("\n"," ");
if (my_a = 1) { printf("Injection into process successfull. PID = %d\n",pid); } else printf("Injection NOT successfull \n");
printf("\n"," "); hModule = EnumModules(pid);
_getch(); // get key stroke
if(0 != hModule) DoHook(pid, true, hModule); // detach from PID
printf("\n"," "); printf("Now detached from process PID = %d\n",pid);
EnumModules(pid); // list out the modules after detach
return 0; }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
In the Export of the DLL the method i want to hook is shown like: "?Method@Class@@QAEJJ@Z"
Is the hooking of an Classmethod of an DLL drifferent to a normal DLL-Function?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I can't find any documentation on the PIMAGE_IMPORT_DESCRIPTOR or PIMAGE_THUNK_DATA structures. I can find there declaration in my WinNT.h file, but I can't find documentation that explains the use of each variable in the structure.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Your approach is exactly what I have been looking for. I just needed the basics to get started with hooking an api funtion and that is exactly what I found with this article. This code works with Vista SP1. Great job!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,through this process can i send message in to the 3rd party application like WM_GETTEXT to a control and get its text or is there any other way to get the controls text (like richedit box). Please help me. thanks in advance.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Is there any method to list all open files in windows system? I refer for example to all text files that are opene with notepad or word.
Radu
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
I have an application provided by a 3rd party, it is made up of 3 components
1) A hardware device connected to my serial port 2) An ActiveX acting as a “Client” that is interacting with that hardware device 3) An ActiveX that is acting as a “Server” component, listens to the Client’s ActiveX messages and sending the relevant commands to some IP address.
I want to trap the “Conversation” between the Client’s ActiveX and the hardware, in an attempt to replace that ActiveX (I don’t have the source code for that ActiveX) and be able to provide that “Bridge” functionality between the hardware device and the “Server” ActiveX myself, using MFC / C++ only
Can this be done? How?
Any help will be appreciated
Thanks Alex
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
i want to catch whatever api call or message generated by third parti application say notepad before these message get dispatch.
mahesh
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi guys, any exper can help me.
How Log external program from my Code where they use API Findwindow ?
Thank you.
|
| Sign In·View Thread·PermaLink | 2.00/5 (2 votes) |
|
|
|
 |
|
|
Hi,
Suppose i hook a function say xyz() and changes the IAT of the corrosponding exeutable. So when a function is called myHookedFunction will be called.
For calling the actual procedure i have to use ::xyz function. Why does ::xyz() does not call the overrided function.
Regards, Sunil Virmani
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
when i cmpile the first file i found errors the error is :
SharedModule.obj : error LNK2001: unresolved external symbol __imp__ImageDirectoryEntryToData@16
how can i fix it
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
I have been able to compile and link, but have not tested yet. All I did was link to imagehlp.lib (shown in the code below). This code is the start of the DLL code (with the added linkage pragma added).
#include #include <imagehlp.h> #include
#pragma comment (lib,"imagehlp.lib")
HANDLE g_hModule = INVALID_HANDLE_VALUE;
.... rest of code cut away
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
Please,
How I get, in this case(below), Full File Name(PATH and File name) from HANDLE of API "CreateFile".
CODE:
PROC g_OriginalCreateFileW; .... ... ... typedef HANDLE WINAPI CreateFileW_t( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile );
HANDLE WINAPI MeuCreateFileW( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ) { HANDLE ReturnValue; time(&tt);
CreateFileW_t* fn = (CreateFileW_t*)g_OriginalCreateFileW; ReturnValue = (*fn)(lpFileName,dwDesiredAccess,dwShareMode,lpSecurityAttributes,dwCreationDisposition,dwFlagsAndAttributes,hTemplateFile);
....... ....... ......
case DLL_PROCESS_ATTACH: g_hModule = hModule; g_OriginalCreateFileW = EnumAndSetHooks("KERNEL32.DLL", "CreateFileW", (PROC)MeuCreateFileW, false, 0);
Help..!!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
| | |