My function:
/*
--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_
runPE(
dosheader ptr,
ntheader ptr,
sectionheader ptr,
ptr to exebuffer,
DWORD SizeOfImage(Alignment fixed))
_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--_--
*/
int runPE2(IMAGE_DOS_HEADER* pDOS,IMAGE_NT_HEADERS * pNT,IMAGE_SECTION_HEADER * pSection,char* pData,DWORD szImage)
{
STARTUPINFO si = {0};
PROCESS_INFORMATION pi;
CONTEXT ctx;
if(CreateProcess(NULL,szFileName,NULL, NULL, 0, CREATE_SUSPENDED, NULL, NULL, &si,&pi))
{
ctx.ContextFlags = CONTEXT_FULL;
if(!GetThreadContext(pi.hThread,&ctx))
{
MessageBoxA(0,"GetThreadContext Error!","Error",0);
}
DWORD dwImagebase = NULL;
DWORD dwBytesRead = NULL;
DWORD dwByteswritten = NULL;
DWORD dwOldProtection = NULL;
if(!ReadProcessMemory(pi.hProcess,(LPVOID)(ctx.Ebx + 8),&dwImagebase,sizeof(DWORD),&dwBytesRead))
{
MessageBoxA(0,"RPM Error!","Error",0);
}
VirtualProtect(&pNT->OptionalHeader.ImageBase,sizeof(DWORD),PAGE_READWRITE,&dwOldProtection);
pNT->OptionalHeader.ImageBase = dwImagebase;
VirtualProtect(&pNT->OptionalHeader.ImageBase,sizeof(DWORD),dwOldProtection,&dwOldProtection);
UnmapViewOfSection_ pZwUnmapViewOfSection = (UnmapViewOfSection_)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwUnmapViewOfSection");
if(pZwUnmapViewOfSection(pi.hProcess, (LPVOID)dwImagebase) != 0)
{
MessageBoxA(0,"Unmaping Error!","Error",0);
}
void* newBase = VirtualAllocEx(pi.hProcess, (LPVOID)pNT->OptionalHeader.ImageBase,szImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(!newBase)
{
MessageBoxA(0,"Allocting Error!","Error",0);
}
if(!WriteProcessMemory(pi.hProcess,(LPVOID)(ctx.Ebx + 8),newBase, sizeof(DWORD), &dwByteswritten))
{
MessageBoxA(0,"WPM Imagebase Error!","Error",0);
}
if(!WriteProcessMemory(pi.hProcess,newBase,pData,pNT->OptionalHeader.SizeOfHeaders, &dwByteswritten))
{
MessageBoxA(0,"WPM SizeOfHeaders Error!","Error",0);
}
for(int i = 0; i < pNT->FileHeader.NumberOfSections; i++)
{
pSection = (PIMAGE_SECTION_HEADER)((char*)(pData + pDOS->e_lfanew + sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) * i));
if(!WriteProcessMemory(pi.hProcess,(char*)(pNT->OptionalHeader.ImageBase + pSection->VirtualAddress),(char*)(pData + pSection->PointerToRawData),pSection->SizeOfRawData, &dwByteswritten))
{
MessageBoxA(0,"WPM in LOOP Error!","Error",0);
}
}
ctx.Eax = (DWORD)newBase + pNT->OptionalHeader.AddressOfEntryPoint; // eax holds new entry point
if(!SetThreadContext(pi.hThread,&ctx))
{
MessageBoxA(0,"SetThreadContext Error!","Error",0);
}
if(!ResumeThread(pi.hThread))
{
MessageBoxA(0,"ResumeThread Error!","Error",0);
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
TerminateProcess(pi.hProcess,0);
return 1;
}
return -1;
}
The error i get after ResumeThread is "The application was unable to start correctly (0xc0000005)
Thanks for reading Hope someone will help
Information:
OS: Win7
compiler VC++ 2010
target application; Simple "Hello World" App; win32 console
Check the VirtualProtect function. Seems that it has been failed. An call the GetLastError(). I think that should be value 0x1e7. Check your base address and addresses in the ".text" section. I have done this by manual processing of import table. Just a simple PE parser and GetProcAddress function. After that you need to calculate your process base address and apply relocation stored in ".reloc" section.
Related
I don't know why I can't unpack the authentification buffer used in CredUIPromptForWindowsCredentials with CredUnPackAuthenticationBufferW, I always get ERROR_INSUFFICIENT_BUFFER error.
I will appreciate your help.
std::wstring caption = L"Caption";
std::wstring msg= L"Msg";
CREDUI_INFOW credui = {};
credui.cbSize = sizeof(credui);
credui.hwndParent = nullptr;
credui.pszMessageText = msg.c_str();
credui.pszCaptionText = caption.c_str();
credui.hbmBanner = nullptr;
ULONG authPackage = 0;
LPVOID outCredBuffer = nullptr;
ULONG outCredSize = 0;
BOOL save = false;
LPWSTR pszUserName = nullptr;
DWORD pcchlMaxUserName = 0;
LPWSTR pszDomainName = nullptr;
DWORD pcchMaxDomainName = 0;
LPWSTR pszPassword = nullptr;
DWORD pcchMaxPassword = 0;
DWORD result = CredUIPromptForWindowsCredentialsW(&credui,
0,
&authPackage,
nullptr,
0,
&outCredBuffer,
&outCredSize,
&save,
CREDUIWIN_ENUMERATE_ADMINS);
std::cout <<CredUnPackAuthenticationBufferW(CRED_PACK_PROTECTED_CREDENTIALS
,outCredBuffer
,outCredSize
,pszUserName
,&pcchlMaxUserName
,pszDomainName
,&pcchMaxDomainName
,pszPassword
,&pcchMaxPassword) << std::endl;
std::cout << GetLastError() << std::endl; // out put 122 == ERROR_INSUFFICIENT_BUFFER
this is typical winapi pattern - api must return some information in the memory buffer. but instead allocate buffer yourself - it obligate caller to allocate buffer.
so caller must allocate buffer itself and pass it pointer and size to api.
api check buffer size - if it large enough fill information to buffer, otherwise return ERROR_INSUFFICIENT_BUFFER (assume that no another errors) or sometime ERROR_MORE_DATA. which which concrete error reurned ERROR_INSUFFICIENT_BUFFER or ERROR_MORE_DATA usual direct documented for api call. different between this 2 errors: ERROR_INSUFFICIENT_BUFFER - mean no any info filled to buffer at all, when ERROR_MORE_DATA mean some data is returned, but incomplete.
and api return to user, via some out parameter, required buffer size in this case. frequently this is done via the same inout parameter - pointer to DWORD. in input specifies the size of user allocated buffer, in output - specifies the required size of buffer or size of returned data
frequently which buffer size is required - unknown at begin. so we need or call api with 0 size buffers(s) first, or allocate some, supposedly sufficient buffer size. if buffer will be insuffient - reallocate or extend it and call api again. for some api (like CredUnPackAuthenticationBufferW) the required output buffer does not change with time (if input parameters not changed), but usual output buffer size may change between calls - even second call with buffer size returned by first call can fail with buffer size error (because returned data may grow between calls). in this case need call api in do/while(error == ERROR_INSUFFICIENT_BUFFER/ERROR_MORE_DATA) loop. but even in case output buffer does not change with time we can better do this is loop with single api call inside, instead 2 api calls.
for concrete case code can look like
ULONG cred()
{
CREDUI_INFO ci = { sizeof(ci) };
BOOL bSave = FALSE;
PVOID pvOutAuthBuffer;
ULONG ulOutAuthBufferSize;
ULONG ulAuthPackage = 0;
ULONG dwError = CredUIPromptForWindowsCredentials(
&ci, NOERROR, &ulAuthPackage, 0, 0,
&pvOutAuthBuffer, &ulOutAuthBufferSize,
&bSave, CREDUIWIN_ENUMERATE_ADMINS );
if (dwError == NOERROR)
{
ULONG cchUserName = 0;
ULONG cchPassword = 0;
ULONG cchDomain = 0;
static volatile UCHAR guz = 0;
PWSTR stack = (PWSTR)alloca(guz);
PWSTR szUserName = 0, szPassword = 0, szDomainName = 0;
ULONG cchNeed, cchAllocated = 0;
do
{
if (cchAllocated < (cchNeed = cchUserName + cchPassword + cchDomain))
{
szUserName = (PWSTR)alloca((cchNeed - cchAllocated) * sizeof(WCHAR));
cchAllocated = (ULONG)(stack - szUserName);
szPassword = szUserName + cchUserName;
szDomainName = szPassword + cchPassword;
}
dwError = CredUnPackAuthenticationBuffer(
CRED_PACK_PROTECTED_CREDENTIALS,
pvOutAuthBuffer, ulOutAuthBufferSize,
szUserName, &cchUserName,
szDomainName, &cchDomain,
szPassword, &cchPassword)
? NOERROR : GetLastError();
if (dwError == NOERROR)
{
DbgPrint("%S#%S %S\n", szDomainName, szUserName, szPassword);
break;
}
} while (dwError == ERROR_INSUFFICIENT_BUFFER);
CoTaskMemFree(pvOutAuthBuffer);
}
return dwError;
}
#RbMm - you're right! I tested it with LogonUser, and it works perfectly. Thanks.
And for a ready solution, I got this :
bool Authenticate_ADMIN_User(std::wstring caption, std::wstring msg, int maxReAsks = 0)
{
CREDUI_INFOW credui = {};
credui.cbSize = sizeof(credui);
credui.hwndParent = nullptr;
credui.pszMessageText = msg.c_str();
credui.pszCaptionText = caption.c_str();
credui.hbmBanner = nullptr;
ULONG authPackage = 0,
outCredSize = 0;
LPVOID outCredBuffer = nullptr;
BOOL save = false;
DWORD err = 0;
int tries = 0;
bool reAsk = false;
do
{
tries++;
if(CredUIPromptForWindowsCredentialsW(&credui,
err,
&authPackage,
nullptr,
0,
&outCredBuffer,
&outCredSize,
&save,
CREDUIWIN_ENUMERATE_ADMINS)
!= ERROR_SUCCESS)
return false;
ULONG cchUserName = 0;
ULONG cchPassword = 0;
ULONG cchDomain = 0;
ULONG cchNeed, cchAllocated = 0;
static volatile UCHAR guz = 0;
PWSTR stack = (PWSTR)alloca(guz);
PWSTR szUserName = nullptr, szPassword = nullptr, szDomainName = nullptr;
BOOL ret;
do{
if (cchAllocated < (cchNeed = cchUserName + cchPassword + cchDomain))
{
szUserName = (PWSTR)alloca((cchNeed - cchAllocated) * sizeof(WCHAR));
cchAllocated = (ULONG)(stack - szUserName);
szPassword = szUserName + cchUserName;
szDomainName = szPassword + cchPassword;
}
ret = CredUnPackAuthenticationBuffer(
CRED_PACK_PROTECTED_CREDENTIALS , outCredBuffer, outCredSize, szUserName, &cchUserName,
szDomainName, &cchDomain, szPassword,
&cchPassword);
}while(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
SecureZeroMemory(outCredBuffer, outCredSize);
CoTaskMemFree(outCredBuffer);
HANDLE handle = nullptr;
if (LogonUser(szUserName,
szDomainName,
szPassword,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
&handle))
{
CloseHandle(handle);
return true;
}
else
{
err = ERROR_LOGON_FAILURE;
reAsk = true;
}
}while(reAsk && tries < maxReAsks);
return false;
}
I used the example from https://github.com/hdeldar/QtCrashDumper and made us of the same in my application. Lately for actual crashes in the application the stack trace has been a little useless.
Another question is the dmp files generated module version does not match. I have double checked the module version and it is the same however the dump file has different versions. File version is 2.8.0.4 and the dmp file has 2.08.0.4
I have looked into a few answers on stackoverflow to not understand what functions I am missing.
CrashDump Info
The KB link does not exist anymore - KB313109
My implementation
#include "CrashDumpDef.h"
#include "version.h"
#ifdef USE_MINI_DUMP
#include "CrashDump.h"
#include "FileSystem.h"
LPCWSTR CrashDump::m_szAppName;
LPWSTR CrashDump::m_szAppVersion;
LPWSTR CrashDump::m_szAppBuildNumber;
WCHAR CrashDump::m_szMessageText[MAX_WARNING_MESSAGE_PATH];
LPWSTR CrashDump::m_szDumpFilePath;
#define DEFAULT_MESSAGE_TEXT L"%s Designer has experienced an issue. \nCrash dump has been saved in %s."
#define MAX_DUMP_FILE_NUMBER 9999
CrashDump::CrashDump(LPCWSTR szAppName, LPCWSTR szVersion, LPCWSTR szBuildNumber)
{
// if this assert fires then you have two instances of CrashDump
// which is not allowed
Q_ASSERT(m_szAppName == NULL);
const char* sz = VER_PRODUCTVERSION_STR;
std::vector<wchar_t> vec;
size_t len = strlen(sz);
vec.resize(len + 1);
mbstowcs(&vec[0], sz, len);
const wchar_t* productVersion = &vec[0];
std::string version = VER_PRODUCTVERSION_STR;
char build = version.back();
const char* buildNum = new char(build);
std::vector<wchar_t> vec1;
size_t lenA = strlen(buildNum);
vec1.resize(lenA + 1);
mbstowcs(&vec1[0], buildNum, lenA);
const wchar_t* buildNumber = &vec1[0];
m_szAppName = szAppName ? wcsdup(szAppName) : wcsdup(L"Designer");
m_szAppVersion = productVersion ? wcsdup(productVersion) : wcsdup(productVersion);
m_szAppBuildNumber = buildNumber ? wcsdup(buildNumber) : wcsdup(buildNumber);
wcscpy(m_szMessageText, DEFAULT_MESSAGE_TEXT);
m_szDumpFilePath = NULL;
::SetUnhandledExceptionFilter(TopLevelFilter);
}
CrashDump::~CrashDump()
{
}
void CrashDump::SetVersion(LPCWSTR szVersion)
{
if (szVersion)
{
free(m_szAppVersion);
m_szAppVersion = wcsdup(szVersion);
}
}
void CrashDump::SetBuildNumber(LPCWSTR szBuildNumber)
{
if (szBuildNumber)
{
free(m_szAppBuildNumber);
m_szAppBuildNumber = wcsdup(szBuildNumber);
}
}
void CrashDump::SetDumpFilePath(LPCWSTR szFilePath)
{
free(m_szDumpFilePath);
{
m_szDumpFilePath = wcsdup(szFilePath);
}
}
LONG CrashDump::TopLevelFilter(struct _EXCEPTION_POINTERS *pExceptionInfo)
{
//::MessageBoxW(NULL, L"debugging", m_szAppName, MB_OK);
LONG retval = EXCEPTION_CONTINUE_SEARCH;
HWND hParent = NULL; // find a better value for your app
// firstly see if dbghelp.dll is around and has the function we need
// look next to the EXE first, as the one in System32 might be old
// (e.g. Windows 2000)
HMODULE hDll = NULL;
WCHAR szDbgHelpPath[_MAX_PATH];
if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH))
{
WCHAR *pSlash = wcsrchr(szDbgHelpPath, L'\\');
if (pSlash)
{
wcscpy(pSlash + 1, L"DBGHELP.DLL");
hDll = ::LoadLibrary(szDbgHelpPath);
}
}
if (hDll == NULL)
{
// load any version we can
hDll = ::LoadLibrary(L"DBGHELP.DLL");
}
LPCWSTR szResult = NULL;
if (hDll)
{
MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(hDll, "MiniDumpWriteDump");
if (pDump)
{
WCHAR szDumpPath[_MAX_PATH];
WCHAR szDumpRootPath[_MAX_PATH];
WCHAR szScratch[_MAX_PATH];
// work out a good place for the dump file - add the path here
if (m_szDumpFilePath == NULL)
{
if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH))
{
WCHAR *pSlash = wcsrchr(szDbgHelpPath, L'\\');
if (pSlash)
{
wcscpy(pSlash + 1, L"");
wcscpy(szDumpPath, szDbgHelpPath);
}
}
//else if (!GetTempPath(_MAX_PATH, szDumpPath))
std::string dmpFile = filesystem::buildFilename(QStringList()
<< QDir::toNativeSeparators(QDir::homePath()) + "\\AppData\\Roaming\\ABC\\logs\\"
).toStdString();
std::wstring wideDmpFile;
for (int i = 0; i < dmpFile.length(); ++i)
wideDmpFile += wchar_t(dmpFile[i]);
const wchar_t* szName = wideDmpFile.c_str();
wcscpy(szDumpPath, szName);
}
else
{
wcscpy(szDumpPath, m_szDumpFilePath);
}
wcscpy(szDumpRootPath, szDumpPath);
//PrintDebug(L"[CrashDump] Mini Dump file:[%s]",szDumpPath);
// ask the user if they want to save a dump file
//if (::MessageBox( NULL, _T("Crash, would you like to save a diagnostic file?"), m_szAppName, MB_YESNO )==IDYES)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
int i = 1;
WCHAR szFileNumber[_MAX_PATH];
while (hFile == INVALID_HANDLE_VALUE)
{
swprintf(szFileNumber, sizeof(szFileNumber), L"_%04d", i);
wcscpy(szDumpPath, szDumpRootPath);
wcscat(szDumpPath, m_szAppName);
wcscat(szDumpPath, L"_");
wcscat(szDumpPath, m_szAppVersion);
wcscat(szDumpPath, L"_");
wcscat(szDumpPath, m_szAppBuildNumber);
wcscat(szDumpPath, szFileNumber);
wcscat(szDumpPath, L".dmp");
hFile = ::CreateFile(szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
i++;
if (i > MAX_DUMP_FILE_NUMBER)
{
hFile = ::CreateFile(szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
break;
}
}
// create the file
if (hFile != INVALID_HANDLE_VALUE)
{
_MINIDUMP_EXCEPTION_INFORMATION ExInfo;
ExInfo.ThreadId = ::GetCurrentThreadId();
ExInfo.ExceptionPointers = pExceptionInfo;
ExInfo.ClientPointers = NULL;
// write the dump
BOOL bOK = pDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL);
if (bOK)
{
swprintf(szScratch, sizeof(szScratch), L"Saved dump file to '%s'", szDumpPath);
szResult = szScratch;
retval = EXCEPTION_EXECUTE_HANDLER;
}
else
{
swprintf(szScratch, sizeof(szScratch), L"Failed to save dump file to '%s' (error %d)", szDumpPath, GetLastError());
szResult = szScratch;
}
::CloseHandle(hFile);
WCHAR csOutMessage[MAX_WARNING_MESSAGE_PATH];
swprintf(csOutMessage, sizeof(csOutMessage), m_szMessageText, m_szAppName, szDumpPath);
//PrintError(_T("%s"), csOutMessage);
::MessageBoxW(NULL, csOutMessage, m_szAppName, MB_OK);
}
else
{
swprintf(szScratch, sizeof(szScratch), L"Failed to create dump file '%s' (error %d)", szDumpPath, GetLastError());
szResult = szScratch;
}
}
}
else
{
szResult = L"DBGHELP.DLL too old";
}
}
else
{
szResult = L"DBGHELP.DLL not found";
}
if (szResult)
{
//PrintDebug(_T("[CrashDump] Mini Dump result:[%s]"),szResult);
}
return retval;
}
#endif
The question is fairly straight forward, what I'm trying to do is restore my process' detoured functions.
When I say detoured I mean the usual jmp instruction to an unknown location.
For example, when the ntdll.dll export NtOpenProcess() is not detoured, the first 5 bytes of the instruction of the function are along the lines of mov eax, *.
(The * offset depending on the OS version.)
When it gets detoured, that mov eax, * turns into a jmp.
What I'm trying to do is restore their bytes to what they were originally before any memory modifications.
My idea was to try and read the information I need from the disk, not from memory, however I do not know how to do that as I'm just a beginner.
Any help or explanation is greatly welcomed, if I did not explain my problem correctly please tell me!
I ended up figuring it out.
Example on NtOpenProcess.
Instead of restoring the bytes I decided to jump over them instead.
First we have to define the base of ntdll.
/* locate ntdll */
#define NTDLL _GetModuleHandleA("ntdll.dll")
Once we've done that, we're good to go. GetOffsetFromRva will calculate the offset of the file based on the address and module header passed to it.
DWORD GetOffsetFromRva(IMAGE_NT_HEADERS * nth, DWORD RVA)
{
PIMAGE_SECTION_HEADER sectionHeader = IMAGE_FIRST_SECTION(nth);
for (unsigned i = 0, sections = nth->FileHeader.NumberOfSections; i < sections; i++, sectionHeader++)
{
if (sectionHeader->VirtualAddress <= RVA)
{
if ((sectionHeader->VirtualAddress + sectionHeader->Misc.VirtualSize) > RVA)
{
RVA -= sectionHeader->VirtualAddress;
RVA += sectionHeader->PointerToRawData;
return RVA;
}
}
}
return 0;
}
We call this to get us the file offset that we need in order to find the original bytes of the function.
DWORD GetExportPhysicalAddress(HMODULE hmModule, char* szExportName)
{
if (!hmModule)
{
return 0;
}
DWORD dwModuleBaseAddress = (DWORD)hmModule;
IMAGE_DOS_HEADER* pHeaderDOS = (IMAGE_DOS_HEADER *)hmModule;
if (pHeaderDOS->e_magic != IMAGE_DOS_SIGNATURE)
{
return 0;
}
IMAGE_NT_HEADERS * pHeaderNT = (IMAGE_NT_HEADERS *)(dwModuleBaseAddress + pHeaderDOS->e_lfanew);
if (pHeaderNT->Signature != IMAGE_NT_SIGNATURE)
{
return 0;
}
/* get the export virtual address through a custom GetProcAddress function. */
void* pExportRVA = GetProcedureAddress(hmModule, szExportName);
if (pExportRVA)
{
/* convert the VA to RVA... */
DWORD dwExportRVA = (DWORD)pExportRVA - dwModuleBaseAddress;
/* get the file offset and return */
return GetOffsetFromRva(pHeaderNT, dwExportRVA);
}
return 0;
}
Using the function that gets us the file offset, we can now read the original export bytes.
size_t ReadExportFunctionBytes(HMODULE hmModule, char* szExportName, BYTE* lpBuffer, size_t t_Count)
{
/* get the offset */
DWORD dwFileOffset = GetExportPhysicalAddress(hmModule, szExportName);
if (!dwFileOffset)
{
return 0;
}
/* get the path of the targetted module */
char szModuleFilePath[MAX_PATH];
GetModuleFileNameA(hmModule, szModuleFilePath, MAX_PATH);
if (strnull(szModuleFilePath))
{
return 0;
}
/* try to open the file off the disk */
FILE *fModule = fopen(szModuleFilePath, "rb");
if (!fModule)
{
/* we couldn't open the file */
return 0;
}
/* go to the offset and read it */
fseek(fModule, dwFileOffset, SEEK_SET);
size_t t_Read = 0;
if ((t_Read = fread(lpBuffer, t_Count, 1, fModule)) == 0)
{
/* we didn't read anything */
return 0;
}
/* close file and return */
fclose(fModule);
return t_Read;
}
And we can retrieve the syscall index from the mov instruction originally placed in the first 5 bytes of the export on x86.
DWORD GetSyscallIndex(char* szFunctionName)
{
BYTE buffer[5];
ReadExportFunctionBytes(NTDLL, szFunctionName, buffer, 5);
if (!buffer)
{
return 0;
}
return BytesToDword(buffer + 1);
}
Get the NtOpenProcess address and add 5 to trampoline over it.
DWORD _ptrNtOpenProcess = (DWORD) GetProcAddress(NTDLL, "NtOpenProcess") + 5;
DWORD _oNtOpenProcess = GetSyscallIndex("NtOpenProcess");
The recovered/reconstructed NtOpenProcess.
__declspec(naked) NTSTATUS NTAPI _NtOpenProcess
(
_Out_ PHANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PCLIENT_ID ClientId
) {
__asm
{
mov eax, [_oNtOpenProcess]
jmp dword ptr ds : [_ptrNtOpenProcess]
}
}
Let's call it.
int main()
{
printf("NtOpenProcess %x index: %x\n", _ptrNtOpenProcess, _oNtOpenProcess);
uint32_t pId = 0;
do
{
pId = GetProcessByName("notepad.exe");
Sleep(200);
} while (pId == 0);
OBJECT_ATTRIBUTES oa;
CLIENT_ID cid;
cid.UniqueProcess = (HANDLE)pId;
cid.UniqueThread = 0;
InitializeObjectAttributes(&oa, NULL, 0, NULL, NULL);
HANDLE hProcess;
NTSTATUS ntStat;
ntStat = _NtOpenProcess(&hProcess, PROCESS_ALL_ACCESS, &oa, &cid);
if (!NT_SUCCESS(ntStat))
{
printf("Couldn't open the process. NTSTATUS: %d", ntStat);
return 0;
}
printf("Successfully opened the process.");
/* clean up. */
NtClose(hProcess);
getchar();
return 0;
}
I scan for opened handles to my process and print them in the console.
I start my process
I attach cheat engine
I run the enumeration of opened handles
I see which process has a handle to my process
The weird issue at this point is as follows, check the code:
array<Accessor^>^ AntiCheat::ScanHandles()
{
List<Accessor^>^ accessorList = gcnew List<Accessor^>();
if (!EnableDebugPrivilege(true))
printf("EnableDebugPrivilege failed: %d\n", GetLastError());
tNtQuerySystemInformation oNtQuerySystemInformation = (tNtQuerySystemInformation)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
PSYSTEM_HANDLE_INFORMATION handleInfo = new SYSTEM_HANDLE_INFORMATION;
SYSTEM_INFORMATION_CLASS infoClass = (SYSTEM_INFORMATION_CLASS)16; // SystemHandleInformation
DWORD size = sizeof(SYSTEM_HANDLE_INFORMATION);
DWORD needed = 0;
NTSTATUS status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
while (!NT_SUCCESS(status))
{
if (needed == 0)
return nullptr;
// The previously supplied buffer wasn't enough.
delete handleInfo;
size = needed + 1024;
handleInfo = (PSYSTEM_HANDLE_INFORMATION)new BYTE[size];
status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
}
HANDLE currentProcess = GetCurrentProcess();
DWORD currentProcessId = GetProcessId(currentProcess);
for (DWORD i = 0; i < handleInfo->dwCount; i++)
{
//printf(".");
SYSTEM_HANDLE handle = handleInfo->Handles[i];
HANDLE procHandle = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, handle.dwProcessId);
if (GetLastError() == ERROR_ACCESS_DENIED)
continue;
HANDLE dupl = 0;
if (!DuplicateHandle(procHandle, (HANDLE)handle.wValue, currentProcess, &dupl, 0, false, DUPLICATE_SAME_ACCESS))
continue;
DWORD procId = GetProcessId(dupl);
if (procId == currentProcessId)
{
printf("accessing us\n");
char processName[MAX_PATH];
GetModuleFileNameEx((HMODULE)procHandle, NULL, processName, MAX_PATH);
accessorList->Add(gcnew Accessor(gcnew String(processName), handle.GrantedAccess));
}
CloseHandle(dupl);
}
return accessorList->ToArray();
}
If I uncomment the line with printf(".");, I see 3 opened handles to my process (cheatengine). If it's commented (runs way faster), there is no opened handle. However I don't know why this affects my code. Im surprised, does anyone know why this happens? Or how to find out how to find the handles without my printf("."); line?
Another issue is: each time I call the function, the number of allocated bytes duplicates. And I don't know why.
I see logic problems with your code.
You are not ignoring array items where handle.dwProcessId equals currentProcessId, so you end up opening handles to your own process. Since you are only interested in looking for other processes, you should be ignoring items where handle.dwProcessId is equal to currentProcessId.
You are not checking if OpenProcess() fails for any reason other than ERROR_ACCESS_DENIED. Do not call GetLastError() unless OpenProcess() actually returns NULL first.
You are not closing an opened handle if DuplicateHandle() fails. And why are you duplicating each source handle just to call GetProcessId() on it? You already have their process IDs from the array, so the whole DuplicateHandle()+GetProcessId() is completely unnecessary.
You are taking the wrong approach anyway. Have a look at this discussion:
Enumerating the processes referencing an object
Use NtQuerySystemInformation with SystemInformationClass set to SystemHandleInformation. This fills in an array of SYSTEM_HANDLE_INFORMATION structures, which are defined as:
typedef struct _SYSTEM_HANDLE_INFORMATION {
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_INFORMATION;
Search for the entry corresponding to the handle you opened with ProcessID equal to GetCurrentProcessId(), then find all entries with the same Object pointer.
Although the discussion shows the wrong declaration for SYSTEM_HANDLE_INFORMATION. The following article shows the correct one:
HOWTO: Enumerate handles
#define SystemHandleInformation 16
typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
/* The following structure is actually called SYSTEM_HANDLE_TABLE_ENTRY_INFO, but SYSTEM_HANDLE is shorter. */
typedef struct _SYSTEM_HANDLE
{
ULONG ProcessId;
BYTE ObjectTypeNumber;
BYTE Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG HandleCount; /* Or NumberOfHandles if you prefer. */
SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
With that said, try something more like this:
array<Accessor^>^ AntiCheat::ScanHandles()
{
List<Accessor^>^ accessorList = gcnew List<Accessor^>();
if (!EnableDebugPrivilege(true))
printf("EnableDebugPrivilege failed: %d\n", GetLastError());
tNtQuerySystemInformation oNtQuerySystemInformation = (tNtQuerySystemInformation) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
DWORD currentProcessId = GetCurrentProcessId();
HANDLE currentProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, currentProcessId);
PVOID currentProcessAddr = nullptr;
DWORD size = sizeof(SYSTEM_HANDLE_INFORMATION);
DWORD needed = 0;
PSYSTEM_HANDLE_INFORMATION handleInfo = (PSYSTEM_HANDLE_INFORMATION) new BYTE[size];
SYSTEM_INFORMATION_CLASS infoClass = (SYSTEM_INFORMATION_CLASS) 16; // SystemHandleInformation
NTSTATUS status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
// The previously supplied buffer wasn't enough.
delete[] handleInfo;
size += 1024;
handleInfo = (PSYSTEM_HANDLE_INFORMATION) new BYTE[size];
status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
}
if (status != 0)
{
delete[] handleInfo;
return nullptr;
}
for (DWORD i = 0; i < handleInfo->dwCount; i++)
{
SYSTEM_HANDLE &handle = handleInfo->Handles[i];
if ((handle.dwProcessId == currentProcessId) &&
(currentProcess == (HANDLE)handle.wValue))
{
currentProcessAddr = handle.pAddress;
break;
}
}
for (DWORD i = 0; i < handleInfo->dwCount; i++)
{
SYSTEM_HANDLE &handle = handleInfo->Handles[i];
if ((handle.dwProcessId != currentProcessId) &&
(handle.pAddress == currentProcessAddr))
{
printf("accessing us\n");
HANDLE procHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, handle.dwProcessId);
if (procHandle != 0)
{
char processName[MAX_PATH+1];
DWORD len = GetModuleFileNameEx((HMODULE)procHandle, NULL, processName, MAX_PATH);
CloseHandle(procHandle);
processName[len] = '\0';
accessorList->Add(gcnew Accessor(gcnew String(processName), handle.GrantedAccess));
}
else
accessorList->Add(gcnew Accessor(gcnew String("unknown"), handle.GrantedAccess));
}
}
CloseHandle(currentProcess);
delete[] handleInfo;
return accessorList->ToArray();
}
I have a Win32 application that gets the HANDLE of a MFC application. My goal is to force the MFC program not to display ASSERT error message box.
Basically, I have made a prototype that allows my Win32 application to force the MFC application to show a message box, just to check if the idea is possible. Now I need to force the MFC application not to display such ASSERT error message boxes.
Is that possible?
You can do this by intercepting the MessageBoxA/MessageBoxW function call. At a usermode level, this is typically done in one of three places:
Call site - There may be more than one call to MessageBox in your executable. You need to find the one that you want to disable. Then you can overwrite the call with code that does nothing (i.e. overwrite with nop instructions).
IAT - The Import Address Table; a table of function pointers filled in by the PE loader. Execution often (but not always) flows through here and replacing the function pointer for MessageBox can allow the MessageBox call to be redirected to some routine that does nothing.
Function entry point - The start of the MessageBox function. This can be located by GetProcAddress and the first instruction replaced with a ret.
The manipulation is done either at runtime (dynamically) or statically (binary rewriting/executable editing) with the first option being far more common. A library which can help you achieve runtime detouring is Microsoft Detours.
This is not a comprehensive list of all the possibilities, but rather the most common methods of execution redirection and detouring.
To my great regret I missed that code. However you still can do it by hands.
Download and install CFF explorer
Open your exe-file with it
Select import directory in sections explorer.
Select USER32.dll in the imported dll list
Select MessageBoxA or MessageBoxW. Edit OFT column. Write there OFT of some "harmless" function. I used GetWindowRect as example.
If you still want an appliaction to do this, I have a code with very similar functionality. It just embeds your dll into import table. You may both edit it to reach wanted result or to use it to redirect MessageBoxW call to your handler.
#include <windows.h>
#include <tchar.h>
#include "stdafx.h"
#include <stdio.h>
DWORD MapFile(HANDLE &FileMapping, LPVOID &FileBegin, const _TCHAR *exeName) {
HANDLE File = CreateFile(exeName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (File == INVALID_HANDLE_VALUE) {
return GetLastError();
}
FileMapping = CreateFileMapping(File, NULL, PAGE_READWRITE, 0, 0, NULL);
CloseHandle(File);
if (!FileMapping) {
return GetLastError();
}
FileBegin = MapViewOfFile(FileMapping, FILE_MAP_WRITE, 0, 0, 0);
if (!FileBegin) {
CloseHandle(FileMapping);
return GetLastError();
}
return 0;
}
DWORD RewriteImportTable(const HANDLE FileMapping, const LPVOID FileBegin, const _TCHAR *dllName, const _TCHAR *funcName, DWORD &finalResult) {
IMAGE_DOS_HEADER* dos_header;
IMAGE_FILE_HEADER* file_header;
IMAGE_OPTIONAL_HEADER* optional_header;
IMAGE_SECTION_HEADER* section_header;
// Counting PE-header offset
dos_header = (IMAGE_DOS_HEADER*) FileBegin;
DWORD PEOffset = dos_header->e_lfanew;
file_header = (IMAGE_FILE_HEADER*) ((DWORD)FileBegin + PEOffset); // file_header must reference "PE\0"
// Checking if we work with PE
_TCHAR* PEString = "PE\0";
if (_tcscmp(PEString, (const _TCHAR*) file_header) != 0) {
printf("This file is not Portable Executable!\n");
return 666;
}
file_header = (IMAGE_FILE_HEADER *)((DWORD)file_header + sizeof(DWORD)); // Ignoring PE
optional_header = (IMAGE_OPTIONAL_HEADER *)((DWORD)file_header + sizeof(IMAGE_FILE_HEADER));
// Finding import section
DWORD ImportRVA = optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
int sectNum = -1;
// Finding import table
section_header = (IMAGE_SECTION_HEADER*) ((DWORD) optional_header + sizeof(IMAGE_OPTIONAL_HEADER));
for (int i = 0; i < (file_header->NumberOfSections); i++) {
if (ImportRVA < (section_header->VirtualAddress)) {
section_header--;
sectNum = i-1;
break;
}
section_header++;
}
if (sectNum == -1) {
printf("This program uses no external libraries! (strange)\n");
return 666;
}
// Getting address of section folowing import section
section_header++;
DWORD SectionNextToImportBegin = (DWORD)FileBegin + section_header->PointerToRawData;
section_header--;
// Getting the address of the import table
LPVOID ImportSectionBegin = (LPVOID) ((DWORD)FileBegin + section_header->PointerToRawData);
// Counting the import table offset in the import section
LPVOID ImportTable = (LPVOID)((DWORD)ImportSectionBegin + (ImportRVA - section_header->VirtualAddress));
IMAGE_IMPORT_DESCRIPTOR *DLLInfo = (IMAGE_IMPORT_DESCRIPTOR*) ImportTable;
LPVOID DLLName;
DWORD DLLCounter = 0;
while (DLLInfo->Name != NULL) {
DLLCounter++;
DLLName = (LPVOID) ((DWORD)ImportSectionBegin + ((DWORD)DLLInfo->Name - section_header->VirtualAddress));
DLLInfo++;
}
printf("Number of imported libraries: %d\n", DLLCounter);
// Counting the size of the future import table
DWORD newImportTableSize = sizeof(IMAGE_IMPORT_DESCRIPTOR) * (DLLCounter + 2);
// Finding the end of the import section
LPVOID pos = (LPVOID) (SectionNextToImportBegin - 1);
DWORD maxFree = 0;
DWORD prevPtr;
LPVOID freePtr = NULL;
// Searching for the free place
while (pos >= ImportSectionBegin) {
if (*(BYTE*)pos == 0) {
prevPtr = (DWORD) pos;
while (*(BYTE*)pos == 0) {
pos = (LPVOID) ((DWORD)pos - 1);
}
if (((DWORD)prevPtr - (DWORD)pos) > maxFree) {
maxFree = ((DWORD)prevPtr - (DWORD)pos);
freePtr = (LPVOID) ((DWORD)pos + 1);
}
}
pos = (LPVOID) ((DWORD)pos - 1);
}
// Modifying pointer: it can refer the tailing zero of some stucture
freePtr = (LPVOID) ((LPDWORD)freePtr + 1);
maxFree -= 4;
// Checking if we have enough space in the import section
if (maxFree < newImportTableSize) {
printf("Not enough free space in Import Section\n");
return 666;
}
printf("Injecting new library...\n");
// Copying old import table on the new place
memcpy(freePtr, ImportTable, sizeof(IMAGE_IMPORT_DESCRIPTOR) * DLLCounter);
// Saving everithing we need on the old place
typedef struct {
DWORD ZeroDword;
DWORD IAT;
DWORD IATEnd;
} MeanStruct;
MeanStruct patch;
patch.ZeroDword = NULL; // this is \0 for dll name
patch.IAT = ImportRVA + _tcslen(dllName) + sizeof(MeanStruct); // RVA to where list of functions begins
patch.IATEnd = NULL;
WORD Hint = 0;
IMAGE_IMPORT_BY_NAME myName;
myName.Hint = 0x00;
myName.Name[0] = 0x00;
LPDWORD zeroPtr = (LPDWORD) ImportTable;
memcpy(zeroPtr, dllName, _tcslen(dllName));
zeroPtr = (LPDWORD) ((DWORD)zeroPtr + strlen(dllName));
memcpy(zeroPtr, &patch, sizeof(patch));
zeroPtr = (LPDWORD) ((DWORD)zeroPtr + sizeof(patch));
finalResult = (DWORD)zeroPtr - (DWORD)ImportSectionBegin + section_header->VirtualAddress;
memcpy(zeroPtr, &Hint, sizeof(WORD));
zeroPtr = (LPDWORD) ((DWORD)zeroPtr + sizeof(WORD));
memcpy(zeroPtr, funcName, strlen(funcName) + 1); // we have no need to write \0 into the end - this is already free space
zeroPtr = (LPDWORD) ((DWORD)zeroPtr + strlen(funcName) + 1);
memcpy(zeroPtr, &myName, sizeof(IMAGE_IMPORT_BY_NAME));
// filling info about dll
IMAGE_IMPORT_DESCRIPTOR myDLL;
// counting RVA for IMAGE_IMPORT_BY_NAME:
DWORD IIBN_Table = ImportRVA + strlen(dllName) + sizeof(DWORD);
// function name pointer
myDLL.Characteristics = IIBN_Table;
myDLL.TimeDateStamp = NULL;
myDLL.ForwarderChain = NULL;
// dll name pointer
myDLL.Name = ImportRVA;
myDLL.FirstThunk = IIBN_Table;
// writting dll info into the new import table
LPVOID oldFreePtr = freePtr;
freePtr = (LPVOID) ((DWORD)freePtr + sizeof(IMAGE_IMPORT_DESCRIPTOR) * DLLCounter);
memcpy(freePtr, &myDLL, sizeof(IMAGE_IMPORT_DESCRIPTOR));
// creating list tail
myDLL.Characteristics = NULL;
myDLL.TimeDateStamp = NULL;
myDLL.ForwarderChain = NULL;
myDLL.Name = NULL;
myDLL.FirstThunk = NULL;
// writing list tail
freePtr = (LPVOID) ((DWORD)freePtr + sizeof(IMAGE_IMPORT_DESCRIPTOR));
memcpy(freePtr, &myDLL, sizeof(IMAGE_IMPORT_DESCRIPTOR));
// setting new import table rva
DWORD newImportTableRVA = (DWORD)oldFreePtr - (DWORD)ImportSectionBegin + section_header->VirtualAddress;
// changing DataDirectory
optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = newImportTableRVA;
optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DLLCounter + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
// clearing non-actual values
optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;
return 0;
}
int _tmain(int argc, _TCHAR *argv[]) {
if (argc != 4) {
printf("Invalid arguments number!!!\n");
return 0;
}
HANDLE FileMapping;
LPVOID FileBegin;
DWORD FileMappingResult = MapFile(FileMapping, FileBegin, argv[1]);
if (0 != FileMappingResult) {
printf("Error of file mapping (%d)\n", FileMappingResult);
if (NULL != FileMapping) CloseHandle(FileMapping);
return FileMappingResult;
}
DWORD functionAddr;
DWORD RewriteImportTableResult = RewriteImportTable(FileMapping, FileBegin, argv[2], argv[3], functionAddr);
if (0 != RewriteImportTableResult) {
UnmapViewOfFile(FileBegin);
CloseHandle(FileMapping);
return 666;
}
printf("Library successfully injected!\n");
printf("Address of injected function: %X", functionAddr);
UnmapViewOfFile(FileBegin);
CloseHandle(FileMapping);
return 0;
}