I'm trying to implement some anti-debugging/anti-reversing techinques in order to prevent my (python) executable to be debugged/reversed, but when I try to launch it from x32dbg or python -m pdb they don't work, letting x32gdb/pdb to access my code and execute the executable/script.
The techniques I'm using are written in c++; I import the c++ code in my python code through a dll generated thorugh Visual Studio 2019, and everything works fine, meaning that I can call the functions in my dll from the executable/python without any error/exception.
I found the techniques online, I didn't wrote them, but also the simplest technique (isDebuggerPresent() function from debugapi.h windows library) does not work, and this is only a call to a function.
Here are the techniques I implemented in my dll
int isThereADebugger()
{
if (IsDebuggerPresent())
{
cout << "Stop debugging program!" << endl;
exit(-1);
}
return 0;
}
// Current PEB for 64bit and 32bit processes accordingly
PVOID GetPEB()
{
#ifdef _WIN64
return (PVOID)__readgsqword(0x0C * sizeof(PVOID));
#else
return (PVOID)__readfsdword(0x0C * sizeof(PVOID));
#endif
}
// Get PEB for WOW64 Process
PVOID GetPEB64()
{
PVOID pPeb = 0;
#ifndef _WIN64
BOOL isWow64 = FALSE;
typedef BOOL(WINAPI* pfnIsWow64Process)(HANDLE hProcess, PBOOL isWow64);
pfnIsWow64Process fnIsWow64Process = (pfnIsWow64Process)
GetProcAddress(GetModuleHandleA("Kernel32.dll"), "IsWow64Process");
if (fnIsWow64Process(GetCurrentProcess(), &isWow64))
{
if (isWow64)
{
pPeb = (PVOID)__readfsdword(0x0C * sizeof(PVOID));
pPeb = (PVOID)((PBYTE)pPeb + 0x1000);
}
}
#endif
return pPeb;
}
#define FLG_HEAP_ENABLE_TAIL_CHECK 0x10
#define FLG_HEAP_ENABLE_FREE_CHECK 0x20
#define FLG_HEAP_VALIDATE_PARAMETERS 0x40
#define NT_GLOBAL_FLAG_DEBUGGED (FLG_HEAP_ENABLE_TAIL_CHECK | FLG_HEAP_ENABLE_FREE_CHECK | FLG_HEAP_VALIDATE_PARAMETERS)
void CheckNtGlobalFlag()
{
PVOID pPeb = GetPEB();
PVOID pPeb64 = GetPEB64();
DWORD offsetNtGlobalFlag = 0;
#ifdef _WIN64
offsetNtGlobalFlag = 0xBC;
#else
offsetNtGlobalFlag = 0x68;
#endif
DWORD NtGlobalFlag = *(PDWORD)((PBYTE)pPeb + offsetNtGlobalFlag);
if (NtGlobalFlag & NT_GLOBAL_FLAG_DEBUGGED)
{
std::cout << "Stop debugging program!" << std::endl;
exit(-1);
}
if (pPeb64)
{
DWORD NtGlobalFlagWow64 = *(PDWORD)((PBYTE)pPeb64 + 0xBC);
if (NtGlobalFlagWow64 & NT_GLOBAL_FLAG_DEBUGGED)
{
std::cout << "Stop debugging program!" << std::endl;
exit(-1);
}
}
}
PIMAGE_NT_HEADERS GetImageNtHeaders(PBYTE pImageBase)
{
PIMAGE_DOS_HEADER pImageDosHeader = (PIMAGE_DOS_HEADER)pImageBase;
return (PIMAGE_NT_HEADERS)(pImageBase + pImageDosHeader->e_lfanew);
}
PIMAGE_SECTION_HEADER FindRDataSection(PBYTE pImageBase)
{
static const std::string rdata = ".rdata";
PIMAGE_NT_HEADERS pImageNtHeaders = GetImageNtHeaders(pImageBase);
PIMAGE_SECTION_HEADER pImageSectionHeader = IMAGE_FIRST_SECTION(pImageNtHeaders);
int n = 0;
for (; n < pImageNtHeaders->FileHeader.NumberOfSections; ++n)
{
if (rdata == (char*)pImageSectionHeader[n].Name)
{
break;
}
}
return &pImageSectionHeader[n];
}
void CheckGlobalFlagsClearInProcess()
{
PBYTE pImageBase = (PBYTE)GetModuleHandle(NULL);
PIMAGE_NT_HEADERS pImageNtHeaders = GetImageNtHeaders(pImageBase);
PIMAGE_LOAD_CONFIG_DIRECTORY pImageLoadConfigDirectory = (PIMAGE_LOAD_CONFIG_DIRECTORY)(pImageBase
+ pImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress);
if (pImageLoadConfigDirectory->GlobalFlagsClear != 0)
{
std::cout << "Stop debugging program!" << std::endl;
exit(-1);
}
}
void CheckGlobalFlagsClearInFile()
{
HANDLE hExecutable = INVALID_HANDLE_VALUE;
HANDLE hExecutableMapping = NULL;
PBYTE pMappedImageBase = NULL;
__try
{
PBYTE pImageBase = (PBYTE)GetModuleHandle(NULL);
PIMAGE_SECTION_HEADER pImageSectionHeader = FindRDataSection(pImageBase);
TCHAR pszExecutablePath[MAX_PATH];
DWORD dwPathLength = GetModuleFileName(NULL, pszExecutablePath, MAX_PATH);
if (0 == dwPathLength) __leave;
hExecutable = CreateFile(pszExecutablePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hExecutable) __leave;
hExecutableMapping = CreateFileMapping(hExecutable, NULL, PAGE_READONLY, 0, 0, NULL);
if (NULL == hExecutableMapping) __leave;
pMappedImageBase = (PBYTE)MapViewOfFile(hExecutableMapping, FILE_MAP_READ, 0, 0,
pImageSectionHeader->PointerToRawData + pImageSectionHeader->SizeOfRawData);
if (NULL == pMappedImageBase) __leave;
PIMAGE_NT_HEADERS pImageNtHeaders = GetImageNtHeaders(pMappedImageBase);
PIMAGE_LOAD_CONFIG_DIRECTORY pImageLoadConfigDirectory = (PIMAGE_LOAD_CONFIG_DIRECTORY)(pMappedImageBase
+ (pImageSectionHeader->PointerToRawData
+ (pImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress - pImageSectionHeader->VirtualAddress)));
if (pImageLoadConfigDirectory->GlobalFlagsClear != 0)
{
std::cout << "Stop debugging program!" << std::endl;
exit(-1);
}
}
__finally
{
if (NULL != pMappedImageBase)
UnmapViewOfFile(pMappedImageBase);
if (NULL != hExecutableMapping)
CloseHandle(hExecutableMapping);
if (INVALID_HANDLE_VALUE != hExecutable)
CloseHandle(hExecutable);
}
}
int GetHeapFlagsOffset(bool x64)
{
return x64 ?
TRUE ? 0x70 : 0x14 : //x64 offsets
TRUE ? 0x40 : 0x0C; //x86 offsets
}
int GetHeapForceFlagsOffset(bool x64)
{
return x64 ?
TRUE ? 0x74 : 0x18 : //x64 offsets
TRUE ? 0x44 : 0x10; //x86 offsets
}
void CheckHeap()
{
PVOID pPeb = GetPEB();
PVOID pPeb64 = GetPEB64();
PVOID heap = 0;
DWORD offsetProcessHeap = 0;
PDWORD heapFlagsPtr = 0, heapForceFlagsPtr = 0;
BOOL x64 = FALSE;
#ifdef _WIN64
x64 = TRUE;
offsetProcessHeap = 0x30;
#else
offsetProcessHeap = 0x18;
#endif
heap = (PVOID) * (PDWORD_PTR)((PBYTE)pPeb + offsetProcessHeap);
heapFlagsPtr = (PDWORD)((PBYTE)heap + GetHeapFlagsOffset(x64));
heapForceFlagsPtr = (PDWORD)((PBYTE)heap + GetHeapForceFlagsOffset(x64));
if (*heapFlagsPtr & ~HEAP_GROWABLE || *heapForceFlagsPtr != 0)
{
std::cout << "Stop debugging program!" << std::endl;
exit(-1);
}
if (pPeb64)
{
heap = (PVOID) * (PDWORD_PTR)((PBYTE)pPeb64 + 0x30);
heapFlagsPtr = (PDWORD)((PBYTE)heap + GetHeapFlagsOffset(true));
heapForceFlagsPtr = (PDWORD)((PBYTE)heap + GetHeapForceFlagsOffset(true));
if (*heapFlagsPtr & ~HEAP_GROWABLE || *heapForceFlagsPtr != 0)
{
std::cout << "Stop debugging program!" << std::endl;
exit(-1);
}
}
}
void trapCheckFlag() {
BOOL isDebugged = TRUE;
__try
{
__asm
{
pushfd
or dword ptr[esp], 0x100 // set the Trap Flag
popfd // Load the value into EFLAGS register
nop
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
// If an exception has been raised – debugger is not present
isDebugged = FALSE;
}
if (isDebugged)
{
std::cout << "Stop debugging program!" << std::endl;
exit(-1);
}
}
int isRemoteDebuggerPresent() {
BOOL isDebuggerPresent = FALSE;
if (CheckRemoteDebuggerPresent(GetCurrentProcess(), &isDebuggerPresent))
{
if (isDebuggerPresent)
{
std::cout << "Stop debugging program!" << std::endl;
exit(-1);
}
}
return 0;
}
typedef NTSTATUS(NTAPI* pfnNtQueryInformationProcess)(
_In_ HANDLE ProcessHandle,
_In_ UINT ProcessInformationClass,
_Out_ PVOID ProcessInformation,
_In_ ULONG ProcessInformationLength,
_Out_opt_ PULONG ReturnLength
);
//const UINT ProcessDebugPort = 7;
int ntQueryInfoProc()
{
pfnNtQueryInformationProcess NtQueryInformationProcess = NULL;
NTSTATUS status;
DWORD isDebuggerPresent = 0;
HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll"));
if (NULL != hNtDll)
{
NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(hNtDll, "NtQueryInformationProcess");
if (NULL != NtQueryInformationProcess)
{
status = NtQueryInformationProcess(
GetCurrentProcess(),
7,
&isDebuggerPresent,
sizeof(DWORD),
NULL);
if (status == 0x00000000 && isDebuggerPresent != 0)
{
std::cout << "Stop debugging program!" << std::endl;
exit(-1);
}
}
}
return 0;
}
typedef NTSTATUS(NTAPI* pfnNtSetInformationThread)(
_In_ HANDLE ThreadHandle,
_In_ ULONG ThreadInformationClass,
_In_ PVOID ThreadInformation,
_In_ ULONG ThreadInformationLength
);
const ULONG ThreadHideFromDebugger = 0x11;
void HideFromDebugger()
{
HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll"));
pfnNtSetInformationThread NtSetInformationThread = (pfnNtSetInformationThread)
GetProcAddress(hNtDll, "NtSetInformationThread");
NTSTATUS status = NtSetInformationThread(GetCurrentThread(),
ThreadHideFromDebugger, NULL, 0);
}
EXCEPTION_DISPOSITION ExceptionRoutine(
PEXCEPTION_RECORD ExceptionRecord,
PVOID EstablisherFrame,
PCONTEXT ContextRecord,
PVOID DispatcherContext)
{
if (EXCEPTION_INVALID_HANDLE == ExceptionRecord->ExceptionCode)
{
std::cout << "Stop debugging program!" << std::endl;
exit(-1);
}
return ExceptionContinueExecution;
}
int handleTracing() {
__asm
{
// set SEH handler
push ExceptionRoutine
push dword ptr fs : [0]
mov dword ptr fs : [0] , esp
}
CloseHandle((HANDLE)0xBAAD);
__asm
{
// return original SEH handler
mov eax, [esp]
mov dword ptr fs : [0] , eax
add esp, 8
}
return 0;
}
#define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A
void dbgMessages() {
WCHAR* outputString = (WCHAR*)L"Any text";
ULONG_PTR args[4] = { 0 };
args[0] = (ULONG_PTR)wcslen(outputString) + 1;
args[1] = (ULONG_PTR)outputString;
__try
{
RaiseException(DBG_PRINTEXCEPTION_WIDE_C, 0, 4, args);
printf("Debugger detected");
exit(-1);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
printf("Debugger NOT detected");
}
}
void DoSmth()
{
Sleep(1000);
}
int timeApproach() {
const int g_doSmthExecutionTime = 1050;
SYSTEMTIME sysTimeStart;
SYSTEMTIME sysTimeEnd;
FILETIME timeStart, timeEnd;
GetSystemTime(&sysTimeStart);
DoSmth();
GetSystemTime(&sysTimeEnd);
SystemTimeToFileTime(&sysTimeStart, &timeStart);
SystemTimeToFileTime(&sysTimeEnd, &timeEnd);
double timeExecution = (timeEnd.dwLowDateTime - timeStart.dwLowDateTime) / 10000.0;
if (timeExecution < g_doSmthExecutionTime)
{
std::cout << "Debugger not present";
}
else
{
std::cout << "Debugger present";
}
return 0;
}
In my python script I call those function sequentially at the entry point, like
if __name__ == "__main__":
antiDebugger = ctypes.CDLL('C:\\absolute\\path\\to\\antiDebugger.dll')
antiDebugger.isThereADebugger()
antiDebugger.CheckNtGlobalFlag()
antiDebugger.CheckGlobalFlagsClearInProcess()
antiDebugger.CheckGlobalFlagsClearInFile()
antiDebugger.CheckHeap()
antiDebugger.trapCheckFlag()
antiDebugger.isRemoteDebuggerPresent()
antiDebugger.ntQueryInfoProc()
antiDebugger.timeApproach()
antiDebugger.handleTracing()
antiDebugger.HideFromDebugger()
antiDebugger.dbgMessages()
customFunction()
Actually, I also tried to put them at the beginning of every function in my python script, but also that didn't work.
I generate the executable with pyarmor combined with pyinstaller using the --onefile option
My windows version is the x64 windows 10 Pro, while my python version is 3.8.2
I know that all those techniques might be too much, but I just want them to work in order to try to break them, specifically the executable side.
Can anyone tell me how to make this techniques work?
Related
I'm using some legacy code to enumerate ports on my machine:
#include <windows.h>
#include <devguid.h>
#include <setupapi.h>
#include <string>
#include <iostream>
#include <assert.h>
bool GetTextProperty( std::string& sProperty,
HDEVINFO dev,
_SP_DEVINFO_DATA* pDeviceInfoData,
DWORD prop )
{
char szBuf[MAX_PATH];
DWORD iPropertySize = 0;
if (SetupDiGetDeviceRegistryProperty(dev, pDeviceInfoData,
prop, 0L, (PBYTE) szBuf, MAX_PATH, &iPropertySize))
{
sProperty = szBuf;
assert( iPropertySize >= sProperty.size() + 1 );
return true;
}
return false;
}
inline bool readRegistryKeyValue( HKEY hKey, const std::string& key, std::string& value )
{
bool res = false;
CHAR szBuffer[512];
DWORD dwBufferSize = sizeof(szBuffer);
ULONG nError = RegQueryValueEx(hKey, key.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize);
if (ERROR_SUCCESS == nError)
{
value = szBuffer;
res = true;
}
return res;
}
void ListPorts()
{
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, 0L, 0L, DIGCF_PRESENT);
if ( hDevInfo == INVALID_HANDLE_VALUE )
{
//Medoc_ReportError(MEDOC_ERROR_HARDWARE_DRIVER_API_FAILED,
// &hDevInfo, sizeof hDevInfo);
assert( false );
}
else
{
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData) != 0; i++)
{
char szBuf[MAX_PATH];
short wImageIdx = 0;
short wItem = 0;
DWORD iPropertySize;
if (SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData,
SPDRP_FRIENDLYNAME, 0L, (PBYTE) szBuf, MAX_PATH, &iPropertySize))
{
std::cout << "Smart name: " << szBuf << std::endl;
HKEY hKey = SetupDiOpenDevRegKey(
hDevInfo,
&DeviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DEV,
KEY_READ );
if ( hKey )
{
std::string portName;
readRegistryKeyValue( hKey, "PortName", portName );
std::cout << "Port name: " << szBuf << std::endl;
for ( DWORD prop = 0; prop != SPDRP_MAXIMUM_PROPERTY; ++prop )
{
std::string temp;
GetTextProperty( temp, hDevInfo, &DeviceInfoData, prop );
std::cout << prop << " : " << temp << std::endl;
}
RegCloseKey(hKey);
}
}
}
}
// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
}
int main( int argc, char* argv[] )
{
ListPorts();
return 0;
}
Among other information, this gives me access to port name (COM*), type (FTDI for instance), VID and PID...
However, when I have many different devices based on a FTDI chip plugged, they all have the same information (SPDRP_HARDWAREID prperty reports FTDIBUS\COMPORT&VID_0403&PID_6015 or FTDIBUS\COMPORT&VID_0403&PID_6010). So I cannot discriminate who is who.
When I use a USB sniffer ("Device Monitoring Studio"), this one is able to report more relevant information withoutestablishing any connection to the ports:
Can this kind of extended information be accessed through Windows API to discriminate by name many devices using the same FTDI chip? Or must I use FTDI driver API to achieve this?
With the help of Ben Voigt and Simon Mourier, I could achieve this, here is the piece of code:
// More includes:
#include <initguid.h>
#include <devpkey.h>
#include <cfgmgr32.h>
// A new dependency:
#pragma comment (lib, "Cfgmgr32.lib")
bool GetDeviceProperty( const std::string& what,
DEVINST dev,
DEVPROPKEY prop )
{
char szDeviceBuf[MAX_PATH];
DEVPROPTYPE type;
ULONG iDevicePropertySize = MAX_PATH;
if ( CM_Get_DevNode_PropertyW(dev,
&prop,
&type,
(PBYTE) szDeviceBuf,
&iDevicePropertySize,
0) == CR_SUCCESS )
{
wchar_t* txt = (wchar_t*) szDeviceBuf;
std::wstring ws(txt);
std::cout << what << " : " << std::string(ws.begin(), ws.end()) << std::endl;
return true;
}
else
{
return false;
}
}
void ListPorts()
{
...
DEVINST devInstParent;
auto status = CM_Get_Parent(&devInstParent, DeviceInfoData.DevInst, 0);
if (status == CR_SUCCESS)
{
ShowDeviceProperty( "Bus reported device description", devInstParent, DEVPKEY_Device_BusReportedDeviceDesc );
ShowDeviceProperty( "Device description", devInstParent, DEVPKEY_Device_DeviceDesc );
}
else
{
continue;
}
...
Well, basically I need to write a DLL in C++ that I will inject into notepad.exe.
This DLL suppose to open a pop-out message or a window with my name in it.
The problem is that I'm kinda new with DLL and I started a week ago. I'm having trouble opening a window or a message with a DLL using "windows.h".
I did try using MessageBox but it's not working.
that's my injector
that i took from: https://www.fxp.co.il/showthread.php?t=15051062
#include <iostream>
#include <direct.h>
#include <windows.h>
#include <Tlhelp32.h>
LPCTSTR SzToLPCTSTR(char* szString);
char* GetCurrentDir();
void WaitForProcessToAppear(LPCTSTR lpcszProc, DWORD dwDeley);
DWORD GetProcessIdByName(LPCTSTR lpcszProc);
BOOL InjectDll(DWORD dwPid, char* szDllPath);
int main()
{
char szProc[MAX_PATH], szDll[MAX_PATH];
char* szDllPath = (char*)malloc(MAX_PATH);
LPTSTR lpszProc = NULL;
while (true)
{
std::cout << "Process: ";
std::cin >> szProc;
std::cout << "DLL Injection: ";
std::cin >> szDll;
szDllPath = GetCurrentDir();
strcat_s(szDllPath, MAX_PATH, "\\");
strcat_s(szDllPath, MAX_PATH, szDll);
std::cout << "Waiting for process..." << std::endl;
WaitForProcessToAppear(SzToLPCTSTR(szProc), 100);
if (InjectDll(GetProcessIdByName(SzToLPCTSTR(szProc)), szDllPath)) std::cout << "Injection succeeded!" << std::endl;
else std::cout << "Injection failed!" << std::endl;
std::cout << "\n";
}
return 0;
}
char* GetCurrentDir()
{
char* szRet = (char*)malloc(MAX_PATH);
_getcwd(szRet, MAX_PATH);
return szRet;
}
LPCTSTR SzToLPCTSTR(char* szString)
{
LPTSTR lpszRet;
size_t size = strlen(szString) + 1;
lpszRet = (LPTSTR)malloc(MAX_PATH);
mbstowcs_s(NULL, lpszRet, size, szString, _TRUNCATE);
return lpszRet;
}
void WaitForProcessToAppear(LPCTSTR lpcszProc, DWORD dwDeley)
{
HANDLE hSnap;
PROCESSENTRY32 peProc;
BOOL bAppeared = FALSE;
while (!bAppeared)
{
if ((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) != INVALID_HANDLE_VALUE)
{
peProc.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnap, &peProc))
while (Process32Next(hSnap, &peProc) && !bAppeared)
if (!lstrcmp(lpcszProc, peProc.szExeFile))
bAppeared = TRUE;
}
CloseHandle(hSnap);
Sleep(dwDeley);
}
}
DWORD GetProcessIdByName(LPCTSTR lpcszProc)
{
HANDLE hSnap;
PROCESSENTRY32 peProc;
DWORD dwRet = -1;
if ((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) != INVALID_HANDLE_VALUE)
{
peProc.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnap, &peProc))
while (Process32Next(hSnap, &peProc))
if (!lstrcmp(lpcszProc, peProc.szExeFile))
dwRet = peProc.th32ProcessID;
}
CloseHandle(hSnap);
return dwRet;
}
BOOL InjectDll(DWORD dwPid, char* szDllPath)
{
DWORD dwMemSize;
HANDLE hProc;
LPVOID lpRemoteMem, lpLoadLibrary;
BOOL bRet = FALSE;
if ((hProc = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, FALSE, dwPid)) != NULL)
{
dwMemSize = strlen(szDllPath) + 1;
if ((lpRemoteMem = VirtualAllocEx(hProc, NULL, dwMemSize, MEM_COMMIT, PAGE_READWRITE)) != NULL)
if (WriteProcessMemory(hProc, lpRemoteMem, (LPCVOID)szDllPath, dwMemSize, NULL))
{
lpLoadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
if (CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpLoadLibrary, lpRemoteMem, 0, NULL) != NULL)
bRet = TRUE;
}
}
CloseHandle(hProc);
return bRet;
}
And that's my DLL:
#include <windows.h>
BOOL WINAPI DllMain( HMODULE hModule,
DWORD fdwReason,
LPVOID lpvReserved
)
{
if (fdwReason == DLL_PROCESS_ATTACH)
MessageBox(NULL, L"Injected by Matan Oshri", L"Hello World", MB_OK);
return TRUE;
}
Please let me know if u see any kind of mistake.
I appreciate all the help I can get.
Thank you.
First I can inject the DLL with the sample code, make sure the Dll, injector.exe and notepad.exe are in the same bits(Usually, notepad.exe starts with 64-bit).
I am getting the error code = 5 if I use 32-bits of DLL or injector.exe with 64-bits notepad.exe
Second, According to the CreateRemoteThread document:
hProcess
A handle to the process in which the thread is to be created. The
handle must have the PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION,
PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ access
rights, and may fail without these rights on certain platforms. For
more information, see Process Security and Access Rights.
(Although the above sample works for me with out PROCESS_QUERY_INFORMATION and PROCESS_VM_READ)
Third, There is something worth improving in your code:
char* szDllPath = (char*)malloc(MAX_PATH);
szDllPath = GetCurrentDir();
/*{
char* szRet = (char*)malloc(MAX_PATH);
_getcwd(szRet, MAX_PATH);
return szRet;
}*/
This will cause the memory of the first application to be leaked.
LPCTSTR SzToLPCTSTR(char* szString);
We could use Unicode string directly.
sample:
#include <iostream>
#include <direct.h>
#include <windows.h>
#include <Tlhelp32.h>
//LPCWSTR SzToLPCTSTR(char* szString);
//char* GetCurrentDir();
void WaitForProcessToAppear(LPCWSTR lpcszProc, DWORD dwDeley);
DWORD GetProcessIdByName(LPCWSTR lpcszProc);
BOOL InjectDll(DWORD dwPid, LPCWSTR szDllPath);
int main()
{
while (true)
{
std::wstring szProc, szDll;
std::wstring szDllPath;
std::wcout << L"Process: ";
std::wcin >> szProc;
std::wcout << L"DLL Injection: ";
std::wcin >> szDll;
WCHAR dir[MAX_PATH] = { 0 };
GetCurrentDirectoryW(MAX_PATH, dir);
szDllPath = dir;
szDllPath += L"\\";
szDllPath += szDll;
std::wcout << L"Waiting for process..." << std::endl;
WaitForProcessToAppear(szProc.c_str(), 100);
if (InjectDll(GetProcessIdByName(szProc.c_str()), szDllPath.c_str())) std::wcout << L"Injection succeeded!" << std::endl;
else std::wcout << L"Injection failed!" << std::endl;
std::wcout << L"\n";
}
return 0;
}
//char* GetCurrentDir()
//{
// char* szRet = (char*)malloc(MAX_PATH);
// _getcwd(szRet, MAX_PATH);
// return szRet;
//}
//LPCWSTR SzToLPCTSTR(char* szString)
//{
// LPTSTR lpszRet;
// size_t size = strlen(szString) + 1;
// lpszRet = (LPTSTR)malloc(MAX_PATH);
// mbstowcs_s(NULL, lpszRet, size, szString, _TRUNCATE);
// return lpszRet;
//}
void WaitForProcessToAppear(LPCWSTR lpcszProc, DWORD dwDeley)
{
HANDLE hSnap;
PROCESSENTRY32 peProc;
BOOL bAppeared = FALSE;
while (!bAppeared)
{
if ((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) != INVALID_HANDLE_VALUE)
{
peProc.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnap, &peProc))
while (Process32Next(hSnap, &peProc) && !bAppeared)
if (!lstrcmp(lpcszProc, peProc.szExeFile))
{
bAppeared = TRUE;
break;
}
}
CloseHandle(hSnap);
Sleep(dwDeley);
}
}
DWORD GetProcessIdByName(LPCWSTR lpcszProc)
{
HANDLE hSnap;
PROCESSENTRY32 peProc;
DWORD dwRet = -1;
if ((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) != INVALID_HANDLE_VALUE)
{
peProc.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnap, &peProc))
while (Process32Next(hSnap, &peProc))
if (!lstrcmp(lpcszProc, peProc.szExeFile))
{
dwRet = peProc.th32ProcessID;
break;
}
}
CloseHandle(hSnap);
return dwRet;
}
BOOL InjectDll(DWORD dwPid, LPCWSTR szDllPath)
{
DWORD dwMemSize;
HANDLE hProc;
LPVOID lpRemoteMem, lpLoadLibrary;
BOOL bRet = FALSE;
if ((hProc = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwPid)) != NULL)
{
dwMemSize = (wcslen(szDllPath) + 1) * sizeof(WCHAR);
if ((lpRemoteMem = VirtualAllocEx(hProc, NULL, dwMemSize, MEM_COMMIT, PAGE_READWRITE)) != NULL)
if (WriteProcessMemory(hProc, lpRemoteMem, (LPCVOID)szDllPath, dwMemSize, NULL))
{
lpLoadLibrary = GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW");
if (CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpLoadLibrary, lpRemoteMem, 0, NULL) != NULL)
bRet = TRUE;
}
}
CloseHandle(hProc);
return bRet;
}
Finally, according to the limitations in DllMain:
Call functions in User32.dll or Gdi32.dll. Some functions load
another DLL, which may not be initialized.
You cannot use MessageBox in DllMain, but you could use OutputDebugStringW instead to show a message, and use DebugView to check the debug string.
DLL:
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
OutputDebugStringW(L"Injected DLL_PROCESS_ATTACH by Matan Oshri");
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Or use Console API to pop up a console:
DWORD dwSize;
WCHAR string[] = L"Hello World";
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
AllocConsole();
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), string, 12, &dwSize, NULL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
I'm trying to write a code in C++ which would display a process ID and base address of some application, PID seems to look correct but base address is 0, which is incorrect. My question is - what's wrong here?
IDE: Code::Blocks
Also to make it even run i had to set up "-lpsapi" in
Settings -> Compiler -> Linker settings -> Other linker options
I was thinking about building this as admin but could't find such option in Code::Block (maybe build-in?)
Console output
Build messages
#define WINVER 0x0501
#include <iostream>
#include <cstdio>
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <Psapi.h>
#include <tlhelp32.h>
using namespace std;
HANDLE GetHandle()
{
string name = "PathOfExile_x64.exe";
DWORD pid = 0;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 process;
ZeroMemory(&process, sizeof(process));
process.dwSize = sizeof(process);
if (Process32First(snapshot, &process))
{
do
{
if (string(process.szExeFile) == name)
{
pid = process.th32ProcessID;
break;
}
} while (Process32Next(snapshot, &process));
}
CloseHandle(snapshot);
if (pid != 0)
{
cout << "pid = " << pid << endl;
return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
}
return NULL;
}
HMODULE GetModule()
{
HMODULE hMods[1024];
HANDLE pHandle = GetHandle();
DWORD cbNeeded;
unsigned int i;
if (EnumProcessModules(pHandle, hMods, sizeof(hMods), &cbNeeded))
{
for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH];
if (GetModuleFileNameEx(pHandle, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
{
string wstrModName = szModName;
string wstrModContain = "PathOfExile_x64.exe";
if (wstrModName.find(wstrModContain) != string::npos)
{
CloseHandle(pHandle);
return hMods[i];
}
}
}
}
return nullptr;
}
int main()
{
HWND WindowHandle = FindWindow(nullptr, "Path of Exile");
DWORD PID;
GetWindowThreadProcessId(WindowHandle, &PID);
PVOID hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, 0, PID);
HMODULE Module = GetModule();
DWORD BaseAddress = (DWORD)Module;
cout << BaseAddress << endl;
}
I would do it like this, tested working. I'm not familiar with the Enum functions, I prefer to use the ToolHelp32Snapshot function
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <tlhelp32.h>
DWORD GetProcId(const char* procName)
{
DWORD procId = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 procEntry;
procEntry.dwSize = sizeof(procEntry);
if (Process32First(hSnap, &procEntry))
{
do
{
if (!_stricmp(procEntry.szExeFile, procName))
{
procId = procEntry.th32ProcessID;
break;
}
} while (Process32Next(hSnap, &procEntry));
}
}
CloseHandle(hSnap);
return procId;
}
uintptr_t GetModuleBaseAddress(DWORD procId, const char* modName)
{
uintptr_t modBaseAddr = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
if (hSnap != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 modEntry;
modEntry.dwSize = sizeof(modEntry);
if (Module32First(hSnap, &modEntry))
{
do
{
if (!_stricmp(modEntry.szModule, modName))
{
modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
break;
}
} while (Module32Next(hSnap, &modEntry));
}
}
CloseHandle(hSnap);
return modBaseAddr;
}
int main()
{
DWORD procId = GetProcId("PathOfExile_x64.exe");
uintptr_t modBase = GetModuleBaseAddress(procId, "PathOfExile_x64.exe");
std::cout << "0x" << std::hex << modBase << std::endl;
std::getchar();
return 0;
}
I'm working in a small antirootkit and i need add a functionality that is:
Delete all files on directory of rootkit and in yours possible subdiretories.
So, firstly is necessary know all these directories and files, right?
To this, i have code below that already make half of this task. He enumerate all directories and files of a specific directory but not "see" subdirectories ( files and folders).
Eg:
Output:
Code:
#include <ntifs.h>
typedef unsigned int UINT;
NTSTATUS EnumFilesInDir()
{
HANDLE hFile = NULL;
UNICODE_STRING szFileName = { 0 };
OBJECT_ATTRIBUTES Oa = { 0 };
NTSTATUS ntStatus = 0;
IO_STATUS_BLOCK Iosb = { 0 };
UINT uSize = sizeof(FILE_BOTH_DIR_INFORMATION);
FILE_BOTH_DIR_INFORMATION *pfbInfo = NULL;
BOOLEAN bIsStarted = TRUE;
RtlInitUnicodeString(&szFileName, L"\\??\\C:\\MyDirectory");
InitializeObjectAttributes(&Oa, &szFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
ntStatus = ZwCreateFile(&hFile, GENERIC_READ | SYNCHRONIZE, &Oa, &Iosb, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(ntStatus)) { return ntStatus; }
pfbInfo = ExAllocatePoolWithTag(PagedPool, uSize, '0000');
if (pfbInfo == NULL)
{
ZwClose(hFile); return STATUS_NO_MEMORY;
}
while (TRUE)
{
lbl_retry:
RtlZeroMemory(pfbInfo, uSize);
ntStatus = ZwQueryDirectoryFile(hFile, 0, NULL, NULL, &Iosb, pfbInfo, uSize, FileBothDirectoryInformation, FALSE, NULL, bIsStarted);
if (STATUS_BUFFER_OVERFLOW == ntStatus) {
ExFreePoolWithTag(pfbInfo, '000');
uSize = uSize * 2;
pfbInfo = ExAllocatePoolWithTag(PagedPool, uSize, '0000');
if (pfbInfo == NULL) { ZwClose(hFile); return STATUS_NO_MEMORY; }
goto lbl_retry;
}
else if (STATUS_NO_MORE_FILES == ntStatus)
{
ExFreePoolWithTag(pfbInfo, '000');
ZwClose(hFile); return STATUS_SUCCESS;
}
else if (STATUS_SUCCESS != ntStatus)
{
ExFreePoolWithTag(pfbInfo, '000');
ZwClose(hFile);
return ntStatus;
}
if (bIsStarted)
{
bIsStarted = FALSE;
}
while (TRUE)
{
WCHAR * szWellFormedFileName = ExAllocatePoolWithTag(PagedPool, (pfbInfo->FileNameLength + sizeof(WCHAR)), '0001');
if (szWellFormedFileName)
{
RtlZeroMemory(szWellFormedFileName, (pfbInfo->FileNameLength + sizeof(WCHAR)));
RtlCopyMemory(szWellFormedFileName, pfbInfo->FileName, pfbInfo->FileNameLength);
//KdPrint(("File name is: %S\n", szWellFormedFileName));
KdPrint((" %S\n", szWellFormedFileName));
ExFreePoolWithTag(szWellFormedFileName, '000');
}
if (pfbInfo->NextEntryOffset == 0) { break; }
pfbInfo += pfbInfo->NextEntryOffset;
}
}
ZwClose(hFile);
ExFreePoolWithTag(pfbInfo, '000');
return ntStatus;
}
So, how do this?
Thank in advance by any help or suggestion.
--------------------------------------------------------EDIT:--------------------------------------------------------------------
I found a possible solution, but i'm getting a BSOD in this line:
if ( (*pDir)->NextEntryOffset)
In KernelFindNextFile method.
Some suggestion?
Here is the code that i found:
#include <ntifs.h>
#include <stdlib.h>
HANDLE KernelCreateFile(IN PUNICODE_STRING pstrFile,IN BOOLEAN bIsDir)
{
HANDLE hFile = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
IO_STATUS_BLOCK StatusBlock = {0};
ULONG ulShareAccess = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
ULONG ulCreateOpt = FILE_SYNCHRONOUS_IO_NONALERT;
OBJECT_ATTRIBUTES objAttrib = {0};
ULONG ulAttributes = OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE;
InitializeObjectAttributes(&objAttrib,pstrFile,ulAttributes,NULL,NULL);
ulCreateOpt |= bIsDir?FILE_DIRECTORY_FILE:FILE_NON_DIRECTORY_FILE;
Status = ZwCreateFile(
&hFile,
GENERIC_ALL,
&objAttrib,
&StatusBlock,
0,
FILE_ATTRIBUTE_NORMAL,
ulShareAccess,
FILE_OPEN_IF,
ulCreateOpt,
NULL,
0);
if (!NT_SUCCESS(Status))
{
return (HANDLE)-1;
}
return hFile;
}
PFILE_BOTH_DIR_INFORMATION KernelFindFirstFile(IN HANDLE hFile,IN ULONG ulLen,OUT PFILE_BOTH_DIR_INFORMATION pDir)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
IO_STATUS_BLOCK StatusBlock = {0};
PFILE_BOTH_DIR_INFORMATION pFileList = (PFILE_BOTH_DIR_INFORMATION)ExAllocatePool(PagedPool,ulLen);
Status = ZwQueryDirectoryFile(
hFile,NULL,NULL,NULL,
&StatusBlock,
pDir,
ulLen,
FileBothDirectoryInformation,
TRUE,
NULL,
FALSE);
RtlCopyMemory(pFileList,pDir,ulLen);
Status = ZwQueryDirectoryFile(
hFile,NULL,NULL,NULL,
&StatusBlock,
pFileList,
ulLen,
FileBothDirectoryInformation,
FALSE,
NULL,
FALSE);
return pFileList;
}
NTSTATUS KernelFindNextFile(IN OUT PFILE_BOTH_DIR_INFORMATION* pDir)
{
if ( (*pDir)->NextEntryOffset)
{
(*pDir)=(PFILE_BOTH_DIR_INFORMATION)((UINT32)(*pDir)+(*pDir)->NextEntryOffset);
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}
void Traversal()
{
UNICODE_STRING ustrFolder = {0};
WCHAR szSymbol[0x512] = L"\\??\\";
UNICODE_STRING ustrPath = RTL_CONSTANT_STRING(L"C:\\MyDirectory");
HANDLE hFile = NULL;
SIZE_T nFileInfoSize = sizeof(FILE_BOTH_DIR_INFORMATION)+270*sizeof(WCHAR);
SIZE_T nSize = nFileInfoSize*0x256;
char strFileName[0x256] = {0};
PFILE_BOTH_DIR_INFORMATION pFileListBuf = NULL;
PFILE_BOTH_DIR_INFORMATION pFileList = NULL;
PFILE_BOTH_DIR_INFORMATION pFileDirInfo = (PFILE_BOTH_DIR_INFORMATION)ExAllocatePool(PagedPool,nSize);
wcscat_s(szSymbol,_countof(szSymbol),ustrPath.Buffer);
RtlInitUnicodeString(&ustrFolder,szSymbol);
hFile = KernelCreateFile(&ustrFolder,TRUE);
pFileList = pFileListBuf;
KernelFindFirstFile(hFile,nSize,pFileDirInfo);
if (pFileList)
{
RtlZeroMemory(strFileName,0x256);
RtlCopyMemory(strFileName,pFileDirInfo->FileName,pFileDirInfo->FileNameLength);
if (strcmp(strFileName,"..")!=0 || strcmp(strFileName,".")!=0)
{
if (pFileDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
DbgPrint("[Directory]%S\n",strFileName);
}
else
{
DbgPrint("[File]%S\n",strFileName);
}
}
}
while (NT_SUCCESS(KernelFindNextFile(&pFileList)))
{
RtlZeroMemory(strFileName,0x256);
RtlCopyMemory(strFileName,pFileList->FileName,pFileList->FileNameLength);
if (strcmp(strFileName,"..")==0 || strcmp(strFileName,".")==0)
{
continue;
}
if (pFileList->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
DbgPrint("[Directory]%S\n",strFileName);
}
else
{
DbgPrint("[File]%S\n",strFileName);
}
}
RtlZeroMemory(strFileName,0x256);
RtlCopyMemory(strFileName,pFileListBuf->FileName,pFileListBuf->FileNameLength);
if (strcmp(strFileName,"..")!=0 || strcmp(strFileName,".")!=0)
{
if (pFileDirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
DbgPrint("[Directory]%S\n",strFileName);
}
else
{
DbgPrint("[File]%S\n",strFileName);
}
ExFreePool(pFileListBuf);
ExFreePool(pFileDirInfo);
}
}
BSOD:
FAULTING_SOURCE_LINE_NUMBER: 263
FAULTING_SOURCE_CODE:
259: }
260:
261: NTSTATUS KernelFindNextFile(IN OUT PFILE_BOTH_DIR_INFORMATION* pDir)
262: {
> 263: if ((*pDir)->NextEntryOffset)
264: {
265: (*pDir) = (PFILE_BOTH_DIR_INFORMATION)((UINT32)(*pDir) + (*pDir)->NextEntryOffset);
266: return STATUS_SUCCESS;
267: }
268:
ok, here code which tested and works. if somebody can not use it or got BSOD - probably problem not in code but in somebody skills
several notes - if you have previous mode kernel - use Nt* api (when exported) but not Zw* api. or Io* api. if you not understand why, or what is your previous mode - better even not try programming in kernel.
mandatory use FILE_OPEN_REPARSE_POINT option or even not try run this code if not understand what is this and why need use
for delete - open files with FILE_DELETE_ON_CLOSE option, for dump only - with FILE_DIRECTORY_FILE option instead.
code yourself used <= 0x1800 bytes of stack in x64 in deepest folders, like c:\Users - so this is ok for kernel, but always check stack space with IoGetRemainingStackSize
i will be not correct every comma in your code, if you can not do this yourself
#define ALLOCSIZE PAGE_SIZE
#ifdef _REAL_DELETE_
#define USE_DELETE_ON_CLOSE FILE_DELETE_ON_CLOSE
#define FILE_ACCESS FILE_GENERIC_READ|DELETE
#else
#define USE_DELETE_ON_CLOSE FILE_DIRECTORY_FILE
#define FILE_ACCESS FILE_GENERIC_READ
#endif
// int nLevel, PSTR prefix for debug only
void ntTraverse(POBJECT_ATTRIBUTES poa, ULONG FileAttributes, int nLevel, PSTR prefix)
{
if (IoGetRemainingStackSize() < PAGE_SIZE)
{
DbgPrint("no stack!\n");
return ;
}
if (!nLevel)
{
DbgPrint("!nLevel\n");
return ;
}
NTSTATUS status;
IO_STATUS_BLOCK iosb;
UNICODE_STRING ObjectName;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName };
DbgPrint("%s[<%wZ>]\n", prefix, poa->ObjectName);
#ifdef _REAL_DELETE_
if (FileAttributes & FILE_ATTRIBUTE_READONLY)
{
if (0 <= NtOpenFile(&oa.RootDirectory, FILE_WRITE_ATTRIBUTES, poa, &iosb, FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT|FILE_OPEN_REPARSE_POINT))
{
static FILE_BASIC_INFORMATION fbi = { {}, {}, {}, {}, FILE_ATTRIBUTE_NORMAL };
NtSetInformationFile(oa.RootDirectory, &iosb, &fbi, sizeof(fbi), FileBasicInformation);
NtClose(oa.RootDirectory);
}
}
#endif//_REAL_DELETE_
if (0 <= (status = NtOpenFile(&oa.RootDirectory, FILE_ACCESS, poa, &iosb, FILE_SHARE_VALID_FLAGS,
FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT|USE_DELETE_ON_CLOSE)))
{
if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (PVOID buffer = ExAllocatePool(PagedPool, ALLOCSIZE))
{
union {
PVOID pv;
PBYTE pb;
PFILE_DIRECTORY_INFORMATION DirInfo;
};
while (0 <= (status = NtQueryDirectoryFile(oa.RootDirectory, NULL, NULL, NULL, &iosb,
pv = buffer, ALLOCSIZE, FileDirectoryInformation, 0, NULL, FALSE)))
{
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
ObjectName.Buffer = DirInfo->FileName;
switch (ObjectName.Length = (USHORT)DirInfo->FileNameLength)
{
case 2*sizeof(WCHAR):
if (ObjectName.Buffer[1] != '.') break;
case sizeof(WCHAR):
if (ObjectName.Buffer[0] == '.') continue;
}
ObjectName.MaximumLength = ObjectName.Length;
#ifndef _REAL_DELETE_
if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
#endif
{
ntTraverse(&oa, DirInfo->FileAttributes, nLevel - 1, prefix - 1);
}
#ifndef _REAL_DELETE_
else
#endif
{
DbgPrint("%s%8I64u <%wZ>\n", prefix, DirInfo->EndOfFile.QuadPart, &ObjectName);
}
} while (NextEntryOffset = DirInfo->NextEntryOffset);
}
ExFreePool(buffer);
if (status == STATUS_NO_MORE_FILES)
{
status = STATUS_SUCCESS;
}
}
}
NtClose(oa.RootDirectory);
}
if (0 > status)
{
DbgPrint("---- %x %wZ\n", status, poa->ObjectName);
}
}
void ntTraverse()
{
char prefix[MAXUCHAR + 1];
memset(prefix, '\t', MAXUCHAR);
prefix[MAXUCHAR] = 0;
STATIC_OBJECT_ATTRIBUTES(oa, "\\??\\c:\\users");
//STATIC_OBJECT_ATTRIBUTES(oa, "\\systemroot");
ntTraverse(&oa, FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_READONLY, MAXUCHAR, prefix + MAXUCHAR);
}
I am running into memory errors when I try to run my C++ program in Visual Studio 2012. I am thinking that this code is the cause (since when I remove it, it runs fine):
void GetMachineHash(CString &strHashHex) {
CMD5 cMD5;
BYTE *szHash = (BYTE*)malloc(48);
LPBYTE szMachineNameHash, szNetworkAddressHash, szVolumeIdHash;
TCHAR szMachineId[100];
DWORD nMachineIdLen = 100;
TCHAR szNetworkAddress[13];
IP_ADAPTER_INFO *pAdapterInfo, *pAdapter = NULL;
DWORD dwRetVal = 0;
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
TCHAR szVolumeId[20];
TCHAR szVolumeName[MAX_PATH];
TCHAR szFileSystemName[MAX_PATH];
DWORD dwSerialNumber = 0;
DWORD dwMaxComponentLen = 0;
DWORD dwFileSystemFlags = 0;
ZeroMemory(szHash, 48);
ZeroMemory(szMachineId, 100);
ZeroMemory(szVolumeId, 20);
ZeroMemory(szVolumeName, MAX_PATH);
ZeroMemory(szFileSystemName, MAX_PATH);
ZeroMemory(szNetworkAddress, 13);
GetComputerName(szMachineId, &nMachineIdLen);
cMD5.Calculate(szMachineId);
szMachineNameHash = cMD5.Hash();
pAdapterInfo = (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO));
if (pAdapterInfo == NULL) {
TRACE(_T("Error allocating memory needed to call GetAdaptersinfo()"));
szNetworkAddressHash = NULL;
}
// Make an initial call to GetAdaptersInfo to get the necessary size into the ulOutBufLen variable
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
if (pAdapterInfo == NULL) {
TRACE(_T("Error allocating memory needed to call GetAdaptersinfo()"));
szNetworkAddressHash = NULL;
}
}
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
pAdapter = pAdapterInfo;
while (pAdapter) {
if (pAdapter->Type != MIB_IF_TYPE_LOOPBACK) {
_stprintf_s(szNetworkAddress, 13, _T("%.2X%.2X%.2X%.2X%.2X%.2X"),
pAdapter->Address[0],
pAdapter->Address[1],
pAdapter->Address[2],
pAdapter->Address[3],
pAdapter->Address[4],
pAdapter->Address[5]
);
break;
}
pAdapter = pAdapter->Next;
}
} else {
TRACE(_T("GetAdaptersInfo() call failed"));
szNetworkAddressHash = NULL;
}
cMD5.Calculate(szNetworkAddress);
szNetworkAddressHash = cMD5.Hash();
if (GetVolumeInformation(
NULL,
szVolumeName,
sizeof(szVolumeName),
&dwSerialNumber,
&dwMaxComponentLen,
&dwFileSystemFlags,
szFileSystemName,
sizeof(szFileSystemName))) {
_stprintf_s(szVolumeId, 20, _T("%lu"), dwSerialNumber);
}
cMD5.Calculate(szVolumeId);
szVolumeIdHash = cMD5.Hash();
// Calculate hash from hashes
memcpy(szHash, szMachineNameHash, 16);
memcpy(szHash+16, szNetworkAddressHash, 16);
memcpy(szHash+32, szVolumeIdHash, 16);
cMD5.Calculate(szHash, 48);
strHashHex.Preallocate(33);
strHashHex = cMD5.HexHash();
free(szHash);
free(pAdapterInfo);
return;
}
And then if I leave the function and just remove this code:
strHashHex.Preallocate(33);
strHashHex = cMD5.HexHash();
Then it will work fine as well. So I am wondering if that is the code that's causing the memory problems, and if it is, how can I fix it?
Here's the CMD5 class (which utilizes the Windows API to generate a MD5 sum):
class CMD5
{
public:
CMD5() {
if(CryptAcquireContext(&m_hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET) == 0){
if(GetLastError() == NTE_EXISTS){
CryptAcquireContext(&m_hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0);
}
}
}
~CMD5() {
if(m_hCryptProv)
CryptReleaseContext(m_hCryptProv, 0);
m_hCryptProv = NULL;
free(m_szHash);
}
bool Calculate(LPCTSTR szText) {
DWORD dwLen = sizeof(TCHAR) * _tcslen(szText);
DWORD dwHashLen;
DWORD dwHashLenSize = sizeof(DWORD);
if (CryptCreateHash(m_hCryptProv, CALG_MD5, 0, 0, &m_hHash)) {
if (CryptHashData(m_hHash, (const BYTE*)szText, dwLen, 0)) {
if (CryptGetHashParam(m_hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, &dwHashLenSize, 0)) {
if(m_szHash = (BYTE*)malloc(dwHashLen)) {
if (CryptGetHashParam(m_hHash, HP_HASHVAL, (BYTE*)m_szHash, &dwHashLen, 0)) {
CryptDestroyHash(m_hHash);
}
}
}
}
}
return false;
}
bool Calculate(const LPBYTE szText, DWORD dwLen) {
DWORD dwHashLen;
DWORD dwHashLenSize = sizeof(DWORD);
if (CryptCreateHash(m_hCryptProv, CALG_MD5, 0, 0, &m_hHash)) {
if (CryptHashData(m_hHash, (const BYTE*)szText, dwLen, 0)) {
if (CryptGetHashParam(m_hHash, HP_HASHSIZE, (BYTE *)&dwHashLen, &dwHashLenSize, 0)) {
if(m_szHash = (BYTE*)malloc(dwHashLen)) {
if (CryptGetHashParam(m_hHash, HP_HASHVAL, (BYTE*)m_szHash, &dwHashLen, 0)) {
CryptDestroyHash(m_hHash);
}
}
}
}
}
return false;
}
LPBYTE Hash() const {
LPBYTE szHash = new BYTE[16];
ZeroMemory(szHash, 16);
memcpy(szHash, m_szHash, 16);
return szHash;
}
LPTSTR HexHash() const {
LPTSTR szBuf = new TCHAR[33];
ZeroMemory(szBuf, 33);
for (int i=0; i<16; i++)
_stprintf_s(szBuf+i*2, 33, _T("%02X"), m_szHash[i]);
szBuf[32]=0;
return szBuf;
}
private:
BYTE *m_szHash;
DWORD m_hHash;
HCRYPTPROV m_hCryptProv;
};
Also, the error I get from VS2012 is Critical error detected c0000374 and the call stack ends with a call to HeapAlloc() from _heap_alloc. Not sure if it matters but this code is being called in a DLL.
It looks like I was able to solve the memory allocation problems by changing the CMD5::HexHash() function to
void HexHash(CString &strHash) {
for (int i=0; i<16; i++)
strHash += StringFormat(_T("%02X"), m_szHash[i]);
return;
}
and call it via cMD5.HexHash(strHashHex);