Difference between QueryVirtualMemoryInformation and VirtualQueryEx - c++

While looking for ways to query specific information about a range of pages in windows I came across two solutions that were used commonly. However these two alternatives seem to return overlapping information.
VirtualQueryEx
Found on MSDN we see that it takes the parameters hProcess, lpAddress, lpBuffer and dwLength to query information for that range of pages. It returns this struct which tells us something about page state, protection and type. Oh well, so a good choice for querying page information right? But wait there is more!
QueryVirtualMemoryInformation
Also found on MSDN and does nearly the same thing. The difference is that it uses a DUMMYSTRUCTNAME and returns a memory structure that overlaps quite perfectly with the struct returned by VirtualQueryEx.
It seems like this could be an oversight and it doesn't matter which one to use. Maybe MS themselves don't even know why there are two overlapping variants inside a single OS. But for someone that does know: What's the difference here?

VirtualQuery and VirtualQueryEx have existed since forever (NT v3.51).
QueryVirtualMemoryInformation is much newer (10 1607) and adds the information class parameter often seen in the NT API. This allows for future expansion. There is currently only one documented class value and the returned information is pretty similar to VirtualQueryEx but not exactly the same (BaseAddress, CommitSize etc).
DUMMYSTRUCTNAME is a compiler thing related to members without a name and has nothing to do with the actual data returned.

exist next NT api - NtQueryVirtualMemory
__kernel_entry NTSYSCALLAPI NTSTATUS NtQueryVirtualMemory(
[in] HANDLE ProcessHandle,
[in, optional] PVOID BaseAddress,
[in] MEMORY_INFORMATION_CLASS MemoryInformationClass,
[out] PVOID MemoryInformation,
[in] SIZE_T MemoryInformationLength,
[out, optional] PSIZE_T ReturnLength
);
where MEMORY_INFORMATION_CLASS can have next values:
enum MEMORY_INFORMATION_CLASS
{
MemoryBasicInformation, // MEMORY_BASIC_INFORMATION
MemoryWorkingSetInformation, // MEMORY_WORKING_SET_INFORMATION
MemoryMappedFilenameInformation, // UNICODE_STRING
MemoryRegionInformation, // MEMORY_REGION_INFORMATION
MemoryWorkingSetExInformation, // MEMORY_WORKING_SET_EX_INFORMATION // since VISTA
MemorySharedCommitInformation, // MEMORY_SHARED_COMMIT_INFORMATION // since WIN8
MemoryImageInformation, // MEMORY_IMAGE_INFORMATION
MemoryRegionInformationEx, // MEMORY_REGION_INFORMATION
MemoryPrivilegedBasicInformation,
MemoryEnclaveImageInformation, // MEMORY_ENCLAVE_IMAGE_INFORMATION // since REDSTONE3
MemoryBasicInformationCapped, // 10
MemoryPhysicalContiguityInformation, // MEMORY_PHYSICAL_CONTIGUITY_INFORMATION // since 20H1
MemoryBadInformation, // since WIN11
MemoryBadInformationAllProcesses, // since 22H1
MaxMemoryInfoClass
} ;
both VirtualQueryEx and QueryVirtualMemoryInformation is thin shell over NtQueryVirtualMemory.
the VirtualQueryEx call NtQueryVirtualMemory with MemoryInformationClass = MemoryBasicInformation
SIZE_T
WINAPI
VirtualQueryEx(
_In_ HANDLE hProcess,
_In_opt_ LPCVOID VirtualAddress,
_Out_writes_bytes_to_(dwLength,return) PMEMORY_BASIC_INFORMATION lpBuffer,
_In_ SIZE_T dwLength
)
{
NTSTATUS status = NtQueryVirtualMemory(hProcess, VirtualAddress, MemoryBasicInformation, dwLength, &dwLength);
if (0 > status)
{
RtlNtStatusToDosError(status);
return 0;
}
return dwLength;
}
the QueryVirtualMemoryInformation call NtQueryVirtualMemory with MemoryInformationClass = MemoryRegionInformationEx. despite MemoryInformationClass parameter still exist, it accept only single value.
BOOL
WINAPI
QueryVirtualMemoryInformation(
_In_ HANDLE Process,
_In_ const VOID* VirtualAddress,
_In_ WIN32_MEMORY_INFORMATION_CLASS MemoryInformationClass,
_Out_writes_bytes_(MemoryInformationSize) PVOID MemoryInformation,
_In_ SIZE_T MemoryInformationSize,
_Out_opt_ PSIZE_T ReturnSize
)
{
NTSTATUS status = MemoryRegionInfo != MemoryInformationClass ? STATUS_INVALID_INFO_CLASS :
NtQueryVirtualMemory(hProcess, VirtualAddress, MemoryRegionInformationEx, MemoryInformationSize, ReturnSize);
if (0 > status)
{
RtlNtStatusToDosError(status);
return FALSE;
}
return TRUE;
}
so because in both case the same NT api called internal - this 2 win32 api very similar.

Related

Running programs using RtlCreateUserProcess only works occasionally

Disclaimer: This questions seems to get downvoted because I should use the normal Win32 API (CreateProcess, ShellExecute). I know about these APIs and I'm aware that RtlCreateUserProcess is not supposed to be called directly. However, the native API is a very relevant topic regarding security, that's why I am researching it.
I'm trying to run programs on Windows using the function RtlCreateUserProcess, exported from ntdll.dll. My code works to run calc.exe, however, after trying to run notepad.exe, I receive an error message that reads The ordinal 345 could not be located in dynamic link library "C:\Windows\SysWOW64\notepad.exe". When trying to run other programs it displays various similar messages, always related to some ordinals or DLLs missing.
My example code looks like this:
#include <windows.h>
#include <iostream>
#include <winternl.h>
typedef struct _SECTION_IMAGE_INFORMATION {
PVOID EntryPoint;
ULONG StackZeroBits;
ULONG StackReserved;
ULONG StackCommit;
ULONG ImageSubsystem;
WORD SubSystemVersionLow;
WORD SubSystemVersionHigh;
ULONG Unknown1;
ULONG ImageCharacteristics;
ULONG ImageMachineType;
ULONG Unknown2[3];
} SECTION_IMAGE_INFORMATION, * PSECTION_IMAGE_INFORMATION;
typedef struct _RTL_USER_PROCESS_INFORMATION {
ULONG Size;
HANDLE ProcessHandle;
HANDLE ThreadHandle;
CLIENT_ID ClientId;
SECTION_IMAGE_INFORMATION ImageInformation;
} RTL_USER_PROCESS_INFORMATION, * PRTL_USER_PROCESS_INFORMATION;
typedef VOID(NTAPI* Func1)(PUNICODE_STRING DestinationString, __drv_aliasesMem PCWSTR SourceString);
typedef NTSTATUS(NTAPI* Func2)(OUT PRTL_USER_PROCESS_PARAMETERS* pProcessParameters, IN PUNICODE_STRING ImagePathName, IN PUNICODE_STRING DllPath OPTIONAL, IN PUNICODE_STRING CurrentDirectory OPTIONAL, IN PUNICODE_STRING CommandLine OPTIONAL, IN PVOID Environment OPTIONAL, IN PUNICODE_STRING WindowTitle OPTIONAL, IN PUNICODE_STRING DesktopInfo OPTIONAL, IN PUNICODE_STRING ShellInfo OPTIONAL, IN PUNICODE_STRING RuntimeData OPTIONAL);
typedef NTSTATUS(NTAPI* Func3)(PUNICODE_STRING NtImagePathName, ULONG Attributes, PRTL_USER_PROCESS_PARAMETERS ProcessParameters, PSECURITY_DESCRIPTOR ProcessSecurityDescriptor, PSECURITY_DESCRIPTOR ThreadSecurityDescriptor, HANDLE ParentProcess, BOOLEAN InheritHandles, HANDLE DebugPort, HANDLE ExceptionPort, PRTL_USER_PROCESS_INFORMATION ProcessInformation);
int main()
{
UNICODE_STRING str;
PRTL_USER_PROCESS_PARAMETERS processparameters;
RTL_USER_PROCESS_INFORMATION processinformation = { 0 };
Func1 RtlInitUnicodeString = (Func1)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlInitUnicodeString");
Func2 RtlCreateProcessParameters = (Func2)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlCreateProcessParameters");
Func3 RtlCreateUserProcess = (Func3)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlCreateUserProcess");
RtlInitUnicodeString(&str, L"\\??\\C:\\Windows\\SysWOW64\\notepad.exe"); //Starting calc.exe works, notepad.exe does not.
RtlCreateProcessParameters(&processparameters, &str, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
NTSTATUS works = RtlCreateUserProcess(&str, OBJ_CASE_INSENSITIVE, processparameters, NULL, NULL, NULL, FALSE, NULL, NULL, &processinformation);
if (NT_SUCCESS(works)) {
ResumeThread(processinformation.ThreadHandle);
//Started application crashes at this point + the error message gets shown
}
else {
std::cout << "Failed" << std::endl;
}
return 0;
}
Unfortunately, there is not much information available about using this function, so I would appreciate any answers on how to use this function correctly.
CreateProcess after create new process do much more job, in particular it create activation context for new process based on exe manifest (BasepConstructSxsCreateProcessMessage + CsrClientCallServer) as result new process have initial activation context, stored in PEB (SystemDefaultActivationContextData and ActivationContextData) but in process created with pure call to RtlCreateUserProcess this fields is empty (0). as result your process loaded ComCtl32.dll from system32 (version 5.82 ) and notepad with activation context - 6+ version.
The ordinal 345 could not be located in dynamic link library
really in ComCtl32.DLL pre 6 version (5.82). 345 - this is TaskDialogIndirect api which exist only in ComCtl32.DLL version 6+. but your process load 5.82.. - calling TaskDialogIndirect loader says ordinal 345 not found
so CreateProcess not a thin shell over RtlCreateUserProcess or NtCreateUserProcess, but big and complex api. at it functional very hard if possible at all implement direct

C++ how to find last (offset - adress) used in processmemory with use readprocessmemory

i use this code to readprocessmemory :
BOOL WINAPI ReadProcessMemory(
_In_ HANDLE hProcess,
_In_ LPCVOID lpBaseAddress,
_Out_ LPVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesRead
);
char value[5];
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, 6500);
{
ReadProcessMemory(hProcess, (LPVOID)105477, value, 5, 0);
}
its work 100%
but i want to know how know last Offset used in processmemory - before i read it
see the picture : enter image description here
the last offset in this processmemory is 7FFE0FFF - but how can i get it before i read the processmemory
Well it MAY work if you are absolutely sure that you CAN read the memory of the other process... anyway it is a quite dangerous method, there are much better IPC APIs to do these things!
Unless you are writing a debugger yourself... in fact ReadProcessMemory is cited here "Process Functions for Debugging" https://msdn.microsoft.com/it-it/library/windows/desktop/ms680549(v=vs.85).aspx

How to copy a file but touch the timestamp on the new copy?

I am using ::CopyFile() to make a copy of a file. It appears the original file's timestamp is being preserved and I would like the copy to set the current timestamp on the copy, i.e. 'touching' it.
Is there a WinAPI way to do this easily?
If you read the MSDN documentation for CopyFile(), there are comments at the bottom that say the following:
File times semantics
This article should document semantics with respect to file creation/modification/access times.
Creation time: if the target file already exists, its' creation time is preserved, otherwise it is set to the current system time.
Last Modification time: always copied from modification time of the source file.
Last Access time: always set to the current system time.
and
Mod-time not always preserved
The modification time is not guaranteed to be set. CopyFileEx does try to set the modification time, but it does NO error checking on it. This means if setting modification time fails internally in CopyFileEx (e.g. with access denied), latter will still returns successful!
So if modification time is important for your scenario (it is for my synchronization program), you have to explicitly call SetFileTime() and check it's return value to be sure.
You should use SetFileTime() to update the copied file's timestamp(s) yourself to make sure they are set to what you want them to be set to. There is an example on MSDN:
Changing a File Time to the Current Time
#include <windows.h>
// SetFileToCurrentTime - sets last write time to current system time
// Return value - TRUE if successful, FALSE otherwise
// hFile - must be a valid file handle
BOOL SetFileToCurrentTime(HANDLE hFile)
{
FILETIME ft;
SYSTEMTIME st;
BOOL f;
GetSystemTime(&st); // Gets the current system time
SystemTimeToFileTime(&st, &ft); // Converts the current system time to file time format
f = SetFileTime(hFile, // Sets last-write time of the file
(LPFILETIME) NULL, // to the converted current system time
(LPFILETIME) NULL,
&ft);
return f;
}
::CopyFile is actually part of windows:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363851%28v=vs.85%29.aspx
It is a convenience function that does copy metadata. There is another way, though less convenient, to copy files using windows. Check out these functions:
ReadFile:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
CreateFile:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx
WriteFile:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747%28v=vs.85%29.aspx
HANDLE WINAPI CreateFile(
_In_ LPCTSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
);
BOOL WINAPI ReadFile(
_In_ HANDLE hFile,
_Out_ LPVOID lpBuffer,
_In_ DWORD nNumberOfBytesToRead,
_Out_opt_ LPDWORD lpNumberOfBytesRead,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
BOOL WINAPI WriteFile(
_In_ HANDLE hFile,
_In_ LPCVOID lpBuffer,
_In_ DWORD nNumberOfBytesToWrite,
_Out_opt_ LPDWORD lpNumberOfBytesWritten,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
So you would open the file with something like this:
CreateFile(<File>, GENERIC_READ, FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL)
Check for a invalid return handle,
Create the new file with something like this:
CreateFile(<File>, GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL)
Check for a invalid return handle,
read the file into a buffer:
ReadFile(handle for file 1, buffer, Buffer size, Destination file,OUT for Bytes Read, NULL)
Then write out the Buffer:
WriteFile(outfile handle,buffer,number of bytes,NULL)
Close your handles.
Make sure to read CreateFiles details, it can be used to open files too.

Visual C++ RegGetValue() fails in program where it shouldn't

I'm making a C++ program using Visual C++ 2008 Express that gets the paths to specific apps from the registry, display a list of those that are installed, allows the user to pick one to configure, then launch the selected app.
This program is supposed to retrieve the paths to (currently) three apps by using RegGetValue (from windows.h).
While it works with Apps n°1 and 3, it fails with app n°2.
The part of the source that handles the registry is available on Pastebin: http://pastebin.com/9X2hjGqh.
I get error n°234 (ERROR_MORE_DATA) when I add a cout to get the function's return.
RegGetValue syntax:
LONG WINAPI RegGetValue(
_In_ HKEY hkey,
_In_opt_ LPCTSTR lpSubKey,
_In_opt_ LPCTSTR lpValue,
_In_opt_ DWORD dwFlags,
_Out_opt_ LPDWORD pdwType,
_Out_opt_ PVOID pvData,
_Inout_opt_ LPDWORD pcbData
);
Full reference here: http://msdn.microsoft.com/en-us/library/ms724875(v=VS.85).aspx
One thing that stands out are all the calls where you do this:
RegGetValue(hKey, NULL, "PATH", RRF_RT_ANY, NULL, (PVOID)&ValueBuffer, &BufferSize);
Notice the last parameter is &BufferSize. This is an [in, out] parameter. You set it to the size of your buffer before going in and it changes the value to the number of characters read into the buffer on the way out. This is what the docs say about RegGetValue (and other similar Reg) functions:
pcbData [in, out, optional]
A pointer to a variable that specifies the size of the buffer pointed to by the pvData parameter, in bytes. When the function returns, this variable contains the size of the data copied to pvData.
So when you call RegGetValue it started at 8192 (BUFFER) but after the first call it was overwritten by the the number of characters read.
Before each RegGetValue call where you pass a &BufferSize you should do this:
BufferSize = BUFFER
As well I notice you have:
#define BUFFER 8192
char ValueBuffer[255];
DWORD BufferSize = BUFFER;
Shouldn't you be setting ValueBuffer to be at least ValueBuffer[BUFFER] instead of ValueBuffer[255]?
As well your code as it is only supports an 8192 byte buffer. If the Value key from the registry is longer than that then it would return ERROR_MORE_DATA. I assume that your code is not anticipating anything beyond 8192. You can determine the size up front for a Value key by using RegQueryInfoKey and dynamically allocating enough space ahead of time.
ERROR_MORE_DATA means that one of the buffers you passed to RegGetValue is not large enough to store the data you asked RegGetValue to give you. You need to loop and reallocate the buffers supplied here when you get this exit code.
For example:
LONG result = ERROR_MORE_DATA;
DWORD dataLength = /* some reasonable default size */ 255;
unique_ptr<char[]> buffer;
while (result == ERROR_MORE_DATA)
{
buffer.reset(new char[dataLength]);
result = RegGetValueW(
hKey,
L"Subkey",
L"Value",
0,
nullptr,
buffer.get(),
&dataLength
);
}
if (result != ERROR_SUCCESS)
{
// Handle the error
}

Detect when a Module (DLL) is unloaded

Is there a way to progammatically detect when a module - specifically a DLL - has been unloaded from a process?
I don't have the DLL source, so I can't change it's DLL entry point. Nor can I poll if the DLL is currently loaded because the DLL may be unloaded and then reloaded between polling.
RESULTS:
I ended up using jimharks solution of detouring the dll entry point and catching DLL_PROCESS_DETACH. I found detouring FreeLibrary() to work as well but code must be added to detect when the module is actually unloaded or if the reference count is just being decreased. Necrolis' link about finding the reference count was handy for on method of doing so.
I should note that I had problems with MSDetours not actually unloading the module from memory if a detour existed within it.
One very bad way(which was used by starcraft 2), is to make your program attach to itsself then monitor for the dll unload debug event(http://msdn.microsoft.com/en-us/library/ms679302(VS.85).aspx), else you'd either need to IAT hook FreeLibrary and FreeLibraryEx in the process or hotpatch the functions in kernel32 them monitor the names being passed and the global reference counts.
Try using LdrRegisterDllNotification if you're on Vista or above. It does require using GetProcAddress to find the function address from ntdll.dll, but it's the proper way of doing it.
Maybe a less bad way then Necrolis's would be to use Microsoft Research's Detours package to hook the dll's entry point to watch for DLL_PROCESS_DETACH notifications.
You can find the entry point given an HMODULE (as returned by LoadLibrary) using this function:
#include <windows.h>
#include <DelayImp.h>
PVOID GetAddressOfEntryPoint(HMODULE hmod)
{
PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)hmod;
PIMAGE_NT_HEADERS pinth = (PIMAGE_NT_HEADERS)((PBYTE)hmod + pidh->e_lfanew);
PVOID pvEntry = (PBYTE)hmod + pinth->OptionalHeader.AddressOfEntryPoint;
return pvEntry;
}
Your entrypoint replacement could take direct action or increment a counter that you check for in your main loop or where it's important to you. (And should almost certainly call the original entrypoint.)
UPDATE: Thanks to #LeoDavidson for pointing this out in the comments below. Detours 4.0 is now licensed using the liberal MIT License.
I hope this helps.
#Necrolis, your link to “The covert way to find the Reference Count of DLL” was just too intriguing for me to ignore because it contains the technical details I needed to implement this alternate solution (that I thought of yesterday, but was lacking the Windows Internals). Thanks. I voted for your answer because of the link you shared.
The linked article shows how to get to the internal LDR_MODULE:
struct _LDR_MODULE
{
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID BaseAddress;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
Right here we have EntryPoint, Window's internal pointer to the module’s entry point. For a dll that’s DllMain (or the language run time function that eventually calls DllMain). What if we just change that? I wrote a test and it seems to work, at least on XP. The DllMain hook gets called with reason DLL_PROCESS_DETACH just before the DLL unloads.
The BaseAddress is the same value as an HMODULE and is useful for finding the right LDR_MODULE. The LoadCount is here so we can track that. And finally FullDllName is helpful for debugging and makes it possible to search for DLL name instead of HMODULE.
This is all Windows internals. It’s (mostly) documented, but the MSDN documentation warns “ZwQueryInformationProcess may be altered or unavailable in future versions of Windows.”
Here’s a full example (but without full error checking). It seems to work but hasn’t seen much testing.
// HookDllEntryPoint.cpp by Jim Harkins (jimhark), Nov 2010
#include "stdafx.h"
#include <stdio.h>
#include <winternl.h>
#include <process.h> // for _beginthread, only needed for testing
typedef NTSTATUS(WINAPI *pfnZwQueryInformationProcess)(
__in HANDLE ProcessHandle,
__in PROCESSINFOCLASS ProcessInformationClass,
__out PVOID ProcessInformation,
__in ULONG ProcessInformationLength,
__out_opt PULONG ReturnLength);
HMODULE hmodNtdll = LoadLibrary(_T("ntdll.dll"));
// Should test pZwQueryInformationProcess for NULL if you
// might ever run in an environment where this function
// is not available (like future version of Windows).
pfnZwQueryInformationProcess pZwQueryInformationProcess =
(pfnZwQueryInformationProcess)GetProcAddress(
hmodNtdll,
"ZwQueryInformationProcess");
typedef BOOL(WINAPI *PDLLMAIN) (
__in HINSTANCE hinstDLL,
__in DWORD fdwReason,
__in LPVOID lpvReserved);
// Note: It's possible for pDllMainNew to be called before
// HookDllEntryPoint returns. If pDllMainNew calls the old
// function, it should pass a pointer to the variable used
// so we can set it here before we hook.
VOID HookDllEntryPoint(
HMODULE hmod, PDLLMAIN pDllMainNew, PDLLMAIN *ppDllMainOld)
{
PROCESS_BASIC_INFORMATION pbi = {0};
ULONG ulcbpbi = 0;
NTSTATUS nts = (*pZwQueryInformationProcess)(
GetCurrentProcess(),
ProcessBasicInformation,
&pbi,
sizeof(pbi),
&ulcbpbi);
BOOL fFoundMod = FALSE;
PLIST_ENTRY pcurModule =
pbi.PebBaseAddress->Ldr->InMemoryOrderModuleList.Flink;
while (!fFoundMod && pcurModule !=
&pbi.PebBaseAddress->Ldr->InMemoryOrderModuleList)
{
PLDR_DATA_TABLE_ENTRY pldte = (PLDR_DATA_TABLE_ENTRY)
(CONTAINING_RECORD(
pcurModule, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks));
// Note: pldte->FullDllName.Buffer is Unicode full DLL name
// *(PUSHORT)&pldte->Reserved5[1] is LoadCount
if (pldte->DllBase == hmod)
{
fFoundMod = TRUE;
*ppDllMainOld = (PDLLMAIN)pldte->Reserved3[0];
pldte->Reserved3[0] = pDllMainNew;
}
pcurModule = pcurModule->Flink;
}
return;
}
PDLLMAIN pDllMain_advapi32 = NULL;
BOOL WINAPI DllMain_advapi32(
__in HINSTANCE hinstDLL,
__in DWORD fdwReason,
__in LPVOID lpvReserved)
{
char *pszReason;
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
pszReason = "DLL_PROCESS_ATTACH";
break;
case DLL_PROCESS_DETACH:
pszReason = "DLL_PROCESS_DETACH";
break;
case DLL_THREAD_ATTACH:
pszReason = "DLL_THREAD_ATTACH";
break;
case DLL_THREAD_DETACH:
pszReason = "DLL_THREAD_DETACH";
break;
default:
pszReason = "*UNKNOWN*";
break;
}
printf("\n");
printf("DllMain(0x%.8X, %s, 0x%.8X)\n",
(int)hinstDLL, pszReason, (int)lpvReserved);
printf("\n");
if (NULL == pDllMain_advapi32)
{
return FALSE;
}
else
{
return (*pDllMain_advapi32)(
hinstDLL,
fdwReason,
lpvReserved);
}
}
void TestThread(void *)
{
// Do nothing
}
// Test HookDllEntryPoint
int _tmain(int argc, _TCHAR* argv[])
{
HMODULE hmodAdvapi = LoadLibrary(L"advapi32.dll");
printf("advapi32.dll Base Addr: 0x%.8X\n", (int)hmodAdvapi);
HookDllEntryPoint(
hmodAdvapi, DllMain_advapi32, &pDllMain_advapi32);
_beginthread(TestThread, 0, NULL);
Sleep(1000);
return 0;
}