Windows Netapi32 - c++

I am currently accessing the Windows Netapi32 using Netapi32.lib, currently I am using c++ to access the api. I am having trouble retrieving the computer name, currently one the NetFileEnum here on FILE_INFO_3 structure here. In the documentation it says,
fi3_username
Pointer to a string that specifies which user (on servers that have user-level security) or which computer (on servers that have
share-level security) opened the resource. Note that Windows does not
support share-level security.This string is Unicode if _WIN32_WINNT or FORCE_UNICODE are defined.
Now, the network that I am running this script in has indeed Share-level security, I am just not sure how to list the computer name.
Relevant code
Library includes:
#pragma comment(lib, "Netapi32.lib")
#include <stdio.h>
#include <assert.h>
#include <windows.h>
#include <lm.h>
Initiate structure:
fstatus is defined in my code as, NET_API_STATUS fStatus, it is the I/O structure. Documentation here
if fstatus is successful the Return value NERR_Success.
If the function fails, the return value can be one of the following error codes.
ERROR_ACCESS_DENIED The user does not have access to the requested
information.
ERROR_INVALID_LEVEL The value specified for the level parameter is
not valid.
ERROR_INVALID_PARAMETER The specified parameter is not valid.
ERROR_MORE_DATA More entries are available. Specify a large enough buffer to receive all entries.
....
more here
To handle that I use if ((fStatus == NERR_Success) || (fStatus == ERROR_MORE_DATA))
The user name could not be found.
fStatus = NetFileEnum(
flServerName, //Pointer to a string that specifies the DNS or NetBIOS name of the remote server on which the function is to execute. If this parameter is NULL, the local computer is used.
flBasePath, //Pointer to a string that specifies a qualifier for the returned information. If this parameter is NULL, all open resources are enumerated.
flUserName, //Pointer to a string that specifies the name of the user or the name of the connection.
dfLevel, //Pointer to a string that specifies the name of the user or the name of the connection. Can be either 2 or 3, I am using 3
(LPBYTE*)&pFile, //Pointer to the address of the buffer that receives the information. The format of this data depends on the value of the level parameter.
fwPrefMaxLen, //pecifies the preferred maximum length of returned data, in bytes.
&fwEntriesRead, //Pointer to a value that receives the count of elements actually enumerated.
&fwTotalEntries, //Pointer to a value that receives the total number of entries that could have been enumerated from the current resume position.
&fwResumeHandle); //Pointer to a value that contains a resume handle which is used to continue an existing file search.
NET_API_STATUS NetFileEnum(
_In_ LMSTR servername,
_In_ LMSTR basepath,
_In_ LMSTR username,
_In_ DWORD level,
_Out_ LPBYTE *bufptr,
_In_ DWORD prefmaxlen,
_Out_ LPDWORD entriesread,
_Out_ LPDWORD totalentries,
_Inout_ PDWORD_PTR resume_handle
);
RAW Values for the above:
NET_API_STATUS fStatus;
LPFILE_INFO_3 pFile = NULL;
LPFILE_INFO_3 pTmpFile;
DWORD dfLevel = 3;
LPTSTR flServerName = NULL;
LPTSTR flUserName = NULL;
LPTSTR flBasePath = NULL;
DWORD fwPrefMaxLen = MAX_PREFERRED_LENGTH;
DWORD fwEntriesRead = 0;
DWORD fwTotalEntries = 0;
DWORD fwResumeHandle = 0;
pTmpfile is the level 3 (documentation here) buffer object,
bufptr [out]
Pointer to the address of the buffer that receives the information. The format of this data depends on the value of the levelparameter.
This buffer returns data in this format,
typedef struct _FILE_INFO_3 {
DWORD fi3_id;
DWORD fi3_permissions;
DWORD fi3_num_locks;
LMSTR fi3_pathname;
LMSTR fi3_username;
} FILE_INFO_3, *PFILE_INFO_3, *LPFILE_INFO_3;
Retrieve data:
printf("\n\tComputer: %S\n", pTmpFile->fi3_username); //how do I retrieve computer name???
printf("\n\tid: %D\n", pTmpFile->fi3_id);
printf("\n\tpath: %S\n", pTmpFile->fi3_pathname);
**It is important to note that I have tried this using vbnet and it works, but somehow cant figure it how to do it on c++.
Complete Test Program:
#ifndef UNICODE
#define UNICODE
#endif
//Initialize the NetAPI Library
#pragma comment(lib, "Netapi32.lib")
#include <stdio.h>
#include <assert.h>
#include <windows.h>
#include <lm.h>
int wmain(int argc, wchar_t *argv[])
{
//NetFile Enum, using 3 Level.
NET_API_STATUS fStatus;
LPFILE_INFO_3 pFile = NULL;
LPFILE_INFO_3 pTmpFile;
DWORD dfLevel = 3;
LPTSTR flServerName = NULL;
LPTSTR flUserName = NULL;
LPTSTR flBasePath = NULL;
DWORD fwPrefMaxLen = MAX_PREFERRED_LENGTH;
DWORD fwEntriesRead = 0;
DWORD fwTotalEntries = 0;
DWORD fwResumeHandle = 0;
DWORD fi;
//
// Check command line arguments.
// Dont need this currently.
//
do
{
fStatus = NetFileEnum(flServerName,
flBasePath,
flUserName,
dfLevel,
(LPBYTE*)&pFile,
fwPrefMaxLen,
&fwEntriesRead,
&fwTotalEntries,
&fwResumeHandle);
if ((fStatus == NERR_Success) || (fStatus == ERROR_MORE_DATA))
{
if ((pTmpFile = pFile) != NULL)
{
for (fi=0; fi < fwEntriesRead; fi++)
{
assert(pTmpFile != NULL);
if (pTmpFile == NULL)
{
fprintf(stderr, "An access violation has occurred\n");
break;
}
printf("\n\tComputer: %S", pTmpFile->fi3_username);
printf("\n\tid: %d", pTmpFile->fi3_id);
printf("\n\tpath: %s", pTmpFile->fi3_pathname);
printf("\n\tLocks: %d\n", pTmpFile->fi3_num_locks);
pTmpFile++;
fwTotalEntries++;
}
}
}
else
fprintf(stderr, "A system error has occurred: %d\n", fStatus);
//
// Free the allocated memory.
//
if (pFile != NULL)
{
NetApiBufferFree(pFile);
pFile = NULL;
}
}
//
// Continue to call NetFilEnum while
// there are more entries.
//
while (fStatus == ERROR_MORE_DATA);
if (pFile != NULL)
NetApiBufferFree(pFile);
return 0;
}
Output:
From Build:
1>------ Build started: Project: Perfmon, Configuration: Release Win32 ------
1>Compiling...
1>file_enumerate.cpp
1>Linking...
1>Generating code
1>Finished generating code
1>Embedding manifest...
1>Build log was saved at "file://...."
1>Perfmon - 0 error(s), 0 warning(s)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
Run:
Computer: User1 //prints only username, not computername (in our system, each user has the same username)
id: 1005687
path: c:\fips\library
Computer: User2 //prints only username, not computername (in our system, each user has the same username)
id: 1005689
path: c:\fips\library\util

If anyone else is wondering about the solution, I figured it out. To query the number of files assoicated with the Computer and not just the User, the NetFileEnum function has to be used, documentation here. The NetFileEnum syntax is shown below,
NET_API_STATUS NetFileEnum(
_In_ LMSTR servername,
_In_ LMSTR basepath,
_In_ LMSTR username,
_In_ DWORD level,
_Out_ LPBYTE *bufptr,
_In_ DWORD prefmaxlen,
_Out_ LPDWORD entriesread,
_Out_ LPDWORD totalentries,
_Inout_ PDWORD_PTR resume_handle
);
Where you have to pass the Computer Name as LMSTR username (you can retrieve the computer name by quering NetSessionEnum(502) which will return all computer names in the network, documentation here ) and the query returns the file details based on the DWORD level, either FILE_INFO_3 documentation here and FILE_INFO_2 documentation here.

Related

Why does SymInitialize() invoke CreateFile()?

Firstly, I want to hook CreateFile() and rewrite it. Then I want to recode the callstack of my new CreateFile() function. But when I use SymInitialize() to Initialize a handle, it falls into an endless loop. Through my debug, the reason is SymInitialize() invokes CreateFile(). So why does SymInitialize() involve CreateFile()? How to avoid this loop? Is there any alternative method to record callstack information to avoid this loop?
#include <windows.h>
#include <stdio.h>
#include "detours.h"
#include <fstream>
#include <io.h>
#pragma comment(lib, "detours.lib")
#include <DbgHelp.h> //SymInitialize
#pragma comment(lib,"dbghelp.lib")
#define STACK_INFO_LEN 200
struct stackInfo {
PDWORD hashValue; // hash value to identify same stack
char* szBriefInfo; // callstack info
};
stackInfo ShowTraceStack(char* szBriefInfo)
{
static const int MAX_STACK_FRAMES = 12;
void* pStack[MAX_STACK_FRAMES];
static char szStackInfo[STACK_INFO_LEN * MAX_STACK_FRAMES];
static char szFrameInfo[STACK_INFO_LEN];
HANDLE process = GetCurrentProcess(); // The handle used must be unique to avoid sharing a session with another component,
SymInitialize(process, NULL, TRUE);
PDWORD hashValue = (PDWORD)malloc(sizeof(DWORD)); // allow memory for hashVavlue, it will be rewrited in function CaptureStackBackTrace
WORD frames = CaptureStackBackTrace(0, MAX_STACK_FRAMES, pStack, hashValue);
//printf("hash value is: %ud \n", &hashValue);
if (szBriefInfo == NULL) {
strcpy_s(szStackInfo, "stack traceback:\n");
}
else {
strcpy_s(szStackInfo, szBriefInfo);
}
for (WORD i = 0; i < frames; ++i) {
DWORD64 address = (DWORD64)(pStack[i]);
DWORD64 displacementSym = 0;
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
DWORD displacementLine = 0;
IMAGEHLP_LINE64 line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymFromAddr(process, address, &displacementSym, pSymbol) &&
SymGetLineFromAddr64(process, address, &displacementLine, &line))
{
_snprintf_s(szFrameInfo, sizeof(szFrameInfo), "\t%s() at %s:%d(0x%x)\n",
pSymbol->Name, line.FileName, line.LineNumber, pSymbol->Address);
}
else
{
_snprintf_s(szFrameInfo, sizeof(szFrameInfo), "\terror: %d\n", GetLastError());
}
strcat_s(szStackInfo, szFrameInfo);
}
stackInfo traceStackInfo;
traceStackInfo.hashValue = hashValue;
traceStackInfo.szBriefInfo = szStackInfo;
return traceStackInfo;
//printf("%s", szStackInfo);
}
HANDLE (*__stdcall oldCreateFile)(LPCWSTR,
DWORD,
DWORD,
LPSECURITY_ATTRIBUTES,
DWORD,
DWORD,
HANDLE) = CreateFileW;
HANDLE WINAPI newCreateFile(
_In_ LPCWSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
) {
ShowTraceStack((char*)"trace information.\n");
return oldCreateFile(
L".\\newFiles.txt", // L".\\NewFile.txt", // Filename
//lpFileName,
dwDesiredAccess, // Desired access
dwShareMode, // Share mode
lpSecurityAttributes, // Security attributes
dwCreationDisposition, // Creates a new file, only if it doesn't already exist
dwFlagsAndAttributes, // Flags and attributes
NULL);
}
void hook() {
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)oldCreateFile, newCreateFile);
DetourTransactionCommit();
}
void unhook()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)oldCreateFile, newCreateFile);
DetourTransactionCommit();
}
void myProcess() {
HANDLE hFile = CreateFile(TEXT(".\\CreateFileDemo.txt"),
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
OutputDebugString(TEXT("CreateFile fail!\r\n"));
}
// write to file
const int BUFSIZE = 4096;
char chBuffer[BUFSIZE];
memcpy(chBuffer, "Test", 4);
DWORD dwWritenSize = 0;
BOOL bRet = WriteFile(hFile, chBuffer, 4, &dwWritenSize, NULL);
if (bRet) {
OutputDebugString(TEXT("WriteFile success!\r\n"));
}
}
int main(){
hook();
myProcess();
unhook();
}
The main problem is the call to SymInitialize where you pass through "TRUE" for fInvadeProcess parameter. This is causing it to SymLoadModuleEx to be called for each loaded module. This will cause a lot of file access to download / create / open PDB files for each loaded module. This is the reason for your infinite loop.
The "quick" fix for this sample is to move the call to SymInitialize into your main before the hook call as it only needs to be called once. This means all the PDB modules are loaded before the hooking / call to ShowTraceStack.
The other problems are:
dbghelp API is NOT thread safe - so this example will not work in a multi-threaded application
SymFromAddr may call CreateFile as well for the same reason to load a newly loaded module PDB information - so your hook not passing through the filename will cause PDB information to not work
If you are trying to make someone more useful I would:
Move SymInitialize to main before the hooking (called only once)
Only call CaptureStackBackTrace in the hook and queue the thread stack information to be processed at a later time
Create a separate thread the takes the CaptureStackBackTrace stack information output and convert it to a stack trace - this would is the only thread calling the dbghlp API making calls to dbghlp API thread safe
In your hook detect when being called from the dbghlp API usage thread and don't do the stack trace and don't modify the CreateFile parameters so you don't get into a infinite loop

GlobalAlloc instead of other allocation method

While going through code on MSDN for finding the owner of the given file object, the program uses GlobalAlloc() to allocate the memory to AcctName. Since I'm new to using the Win32 API, my curiosity made me enquired why we are using GlobalAlloc() instead of other allocation methods. If other better allocation methods exist, how to use them in the given code?
#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#include "accctrl.h"
#include "aclapi.h"
#pragma comment(lib, "advapi32.lib")
int main(void)
{
DWORD dwRtnCode = 0;
PSID pSidOwner = NULL;
BOOL bRtnBool = TRUE;
LPTSTR AcctName = NULL;
LPTSTR DomainName = NULL;
DWORD dwAcctName = 1, dwDomainName = 1;
SID_NAME_USE eUse = SidTypeUnknown;
HANDLE hFile;
PSECURITY_DESCRIPTOR pSD = NULL;
// Get the handle of the file object.
hFile = CreateFile(
TEXT("myfile.txt"),
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Check GetLastError for CreateFile error code.
if (hFile == INVALID_HANDLE_VALUE) {
DWORD dwErrorCode = 0;
dwErrorCode = GetLastError();
_tprintf(TEXT("CreateFile error = %d\n"), dwErrorCode);
return -1;
}
// Get the owner SID of the file.
dwRtnCode = GetSecurityInfo(
hFile,
SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION,
&pSidOwner,
NULL,
NULL,
NULL,
&pSD);
// Check GetLastError for GetSecurityInfo error condition.
if (dwRtnCode != ERROR_SUCCESS) {
DWORD dwErrorCode = 0;
dwErrorCode = GetLastError();
_tprintf(TEXT("GetSecurityInfo error = %d\n"), dwErrorCode);
return -1;
}
// First call to LookupAccountSid to get the buffer sizes.
bRtnBool = LookupAccountSid(
NULL, // local computer
pSidOwner,
AcctName,
(LPDWORD)&dwAcctName,
DomainName,
(LPDWORD)&dwDomainName,
&eUse);
// Reallocate memory for the buffers.
AcctName = (LPTSTR)GlobalAlloc(
GMEM_FIXED,
dwAcctName);
// Check GetLastError for GlobalAlloc error condition.
if (AcctName == NULL) {
DWORD dwErrorCode = 0;
dwErrorCode = GetLastError();
_tprintf(TEXT("GlobalAlloc error = %d\n"), dwErrorCode);
return -1;
}
DomainName = (LPTSTR)GlobalAlloc(
GMEM_FIXED,
dwDomainName);
// Check GetLastError for GlobalAlloc error condition.
if (DomainName == NULL) {
DWORD dwErrorCode = 0;
dwErrorCode = GetLastError();
_tprintf(TEXT("GlobalAlloc error = %d\n"), dwErrorCode);
return -1;
}
// Second call to LookupAccountSid to get the account name.
bRtnBool = LookupAccountSid(
NULL, // name of local or remote computer
pSidOwner, // security identifier
AcctName, // account name buffer
(LPDWORD)&dwAcctName, // size of account name buffer
DomainName, // domain name
(LPDWORD)&dwDomainName, // size of domain name buffer
&eUse); // SID type
// Check GetLastError for LookupAccountSid error condition.
if (bRtnBool == FALSE) {
DWORD dwErrorCode = 0;
dwErrorCode = GetLastError();
if (dwErrorCode == ERROR_NONE_MAPPED)
_tprintf(TEXT
("Account owner not found for specified SID.\n"));
else
_tprintf(TEXT("Error in LookupAccountSid.\n"));
return -1;
} else if (bRtnBool == TRUE)
// Print the account name.
_tprintf(TEXT("Account owner = %s\n"), AcctName);
return 0;
}
See this Microsoft documentation page for an overview of the different memory allocation functions that currently exist in Microsoft Windows.
Basically, GlobalAlloc is a remnant of 16-bit Windows. In 32-bit and 64-bit Windows, there is no longer a distinction between GlobalAlloc and LocalAlloc, as modern operating systems use a flat memory model. If you are interested in what significance these functions had in 16-bit Windows, you can read this article by Microsoft blogger Raymond Chen.
As stated in the offical documentation of the function GlobalAlloc, this function should generally not be used in modern 32-bit or 64-bit applications, except in situations where the documentation specifically tells you to do so.
Since the official documentation on the function LookupAccountSid does not specify that any of the passed buffers must have been allocated with GlobalAlloc, there is no reason to use this function. It would be more appropriate to for example use the function HeapAlloc, as this function has lower overhead than GlobalAlloc. Alternatively, you can use normal C++ memory allocations (for example new or std::vector), which, depending on the implementation, probably calls the function HeapAlloc indirectly.
Thanks for everyone.
I have just modified my code by using malloc.
AccountBuff = (LPSTR)malloc(AccountBufflength * sizeof(LPSTR));
DomainBuff = (LPSTR)malloc(DomainBufflength * sizeof(LPSTR));

CreateRemoteThread MessageBoxA causes remote process to crash

I made a simple program that calculates the RVA of the function MessaegBoxA in user32.dll and then adds that offset to the base loading address of the dll in the remote process's memory to get the address of the function MessageBoxA. I made a dummy program that outputs the address of the function in its memory using GetProcAddress and then implement my own function in my program to display the address it calculated for the same function in the remote process. They always match so I'm certain my function for finding the address of MessageBoxA in remote process's is not the problem.
I made a struct that contains all the necessary information and parameters needed for ThreadProc to execute MessageBoxA in the remote process once I load it using WriteProcessMemory.
typedef struct
{
typedef int (WINAPI* _MessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
_MessageBoxA MessageBoxA;
//These are the four parameters passed to MessageBoxA
HWND hwnd;
LPCSTR msg;
LPCSTR caption;
UINT mb;
}MB_DATA, *PMB_DATA;
When I try this on my own dummy program, the message box shows up but with weird text contrary to the strings I specified in the msg and caption members of MB_DATA. It says the following for the caption asic_string::erase and for the message it says u). And when I try to do this in any other process than my dummy process it crashes the remote process. I made a function to iterate through the modules that have been loaded in the process with tlhelp32 functions to make sure user32.dll is present and it is and my function for finding the address of the function in the process doesn't return NULL like it would if the dll were not present.
Here all relevant functions and my main function:
dependencies.hpp
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <iostream>
using namespace std;
typedef struct
{
typedef int (WINAPI* _MessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
_MessageBoxA MessageBoxA;
HWND hwnd;
LPCSTR msg;
LPCSTR caption;
UINT mb;
}MB_DATA, *PMB_DATA;
//Map the dll into memory
void* GetFileImage(char path[])
{
HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if(hFile == INVALID_HANDLE_VALUE){printf("Error getting file handle: %d", (int)GetLastError());return NULL;}
HANDLE file_map = CreateFileMapping(hFile, NULL, PAGE_READONLY|SEC_IMAGE, 0, 0, "KernelMap");
if(file_map == INVALID_HANDLE_VALUE){printf("Error mapping file: %d", (int)GetLastError());return NULL;}
LPVOID file_image = MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 0);
if(file_image == 0){printf("Error getting mapped view: %d", (int)GetLastError());return NULL;}
return file_image;
}
//Get to the function export directory and find the offset for the specified function from the
//address in memory the dll was loaded at
DWORD_PTR RVAddress(char* image, const char* proc_name)
{
PIMAGE_DOS_HEADER pDos_hdr = (PIMAGE_DOS_HEADER)image;
PIMAGE_NT_HEADERS pNt_hdr = (PIMAGE_NT_HEADERS)(image+pDos_hdr->e_lfanew);
IMAGE_OPTIONAL_HEADER opt_hdr = pNt_hdr->OptionalHeader;
IMAGE_DATA_DIRECTORY exp_entry = opt_hdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
PIMAGE_EXPORT_DIRECTORY pExp_dir = (PIMAGE_EXPORT_DIRECTORY)(image+exp_entry.VirtualAddress);
DWORD* func_table = (DWORD*)(image+pExp_dir->AddressOfFunctions);
WORD* ord_table = (WORD*)(image+pExp_dir->AddressOfNameOrdinals);
DWORD* name_table = (DWORD*)(image+pExp_dir->AddressOfNames);
for(u_int i=0;i<pExp_dir->NumberOfNames;i++)
{
char* name = (char*)(image+name_table[i]);
if(strcmp(proc_name, name) == 0)
{
return (DWORD_PTR)func_table[ord_table[i]];
}
}
return (DWORD_PTR)0;
}
//Add the RVA returned from RVAddress to the address of the dll to find the function in the
//process memory
LPVOID GetProcAddressEx(DWORD dwPid, char* mod_path, char* function_name, char* mod_name)
{
HANDLE hSnapshot = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
me32.dwSize = sizeof(MODULEENTRY32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32, dwPid);
if(hSnapshot == INVALID_HANDLE_VALUE){printf("Snapshot failed");return 0;}
if(!(Module32First(hSnapshot, &me32)))
{
printf("Mod32First failed");
return 0;
}
BOOL found = FALSE;
while(Module32Next(hSnapshot, &me32))
{
if(stricmp(me32.szModule, mod_name) == 0)
{
CloseHandle(hSnapshot);
found = TRUE;
break;
}
}
if(found == FALSE){return 0;}
DWORD_PTR RVA = (DWORD_PTR)RVAddress((char*)GetFileImage(mod_path), function_name);
LPVOID func_addr = me32.modBaseAddr+RVA;
return func_addr;
}
main.cpp
#include "dependencies.hpp"
#define FUNC_SIZE 1024
typedef int (WINAPI* _MessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
int main()
{
MB_DATA mb_data;
mb_data.hwnd = NULL;
mb_data.msg = "Hey";
mb_data.caption = "Yo";
mb_data.mb = MB_OK;
SIZE_T nBytes = 0;
char proc_path[MAX_PATH];
char kernel_path[MAX_PATH];
char user32_path[MAX_PATH];
//get full path to the current process and store it in proc_path
GetModuleFileName(GetModuleHandle(NULL), proc_path, MAX_PATH);
//get full path to kernel32.dll and store it in kernel_path
GetModuleFileName(GetModuleHandle("kernel32.dll"), kernel_path, MAX_PATH);
//get full path to user3.dll and store it in user32_path
GetModuleFileName(GetModuleHandle("user32.dll"), user32_path, MAX_PATH);
//show all processes running and their PID's
system("tasklist");
DWORD dwPid = 0;
printf("PID: ");
scanf("%lu", &dwPid);
//if dwPid is 0 assign it the pid of the current process
if(dwPid == 0)
{
dwPid = GetCurrentProcessId();
}
//Get a handle to the process with all access rights
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
//make sure the handle is valid
if(hProc == NULL){printf("Error obtaining handle to process: %lu", GetLastError());return 1;}
//Get the address of the function in the remote process
LPVOID _MessageBoxA1 = GetProcAddressEx(dwPid, user32_path, (char*)"MessageBoxA", (char*)"user32.dll");
//assign the pointer to the address to the member MessageBoxA of the MB_DATA structure
mb_data.MessageBoxA = (_MessageBoxA)_MessageBoxA1;
//allocate 2mb for our the ThreadProc callback function and the MB_DATA structure
LPVOID lpBase = VirtualAllocEx(hProc, NULL, 2048, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
//did the allocation work
if(lpBase == NULL){printf("Error allocating space: %lu", GetLastError());return 1;}
//so I can check what was written with CheatEngine
cout << "Base address of memory allocated in remote process: " << lpBase << endl;
//Write the function into memory
if(WriteProcessMemory(hProc, lpBase, (LPVOID)ThreadProc, FUNC_SIZE, &nBytes) == 0)
{
printf("Error writing function to process");
return 1;
}
//the address the space left after having written ThreadProc into memory
LPVOID lpBuffer = lpBase+FUNC_SIZE;
//Write the MB_DATA structure into the memory of the remote process
if(WriteProcessMemory(hProc, lpBuffer, &mb_data, sizeof(MB_DATA), &nBytes) == 0)
{
printf("Error writing buffer to process");
}
//Run the ThreadProc function passing the MB_DATA structure to it as its lpParam parameter
if(CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpBase, lpBuffer, 0, NULL) == NULL)
{
printf("Error creating remote thread: %lu", GetLastError());
return 1;
}
//print a list of all the dll's being used by the process
EnumerateModules(dwPid);
system("pause");
return 0;
}
Any help would be greatly appreciated. Thank you very much! :)
mb_data.msg and mb_data.caption point to what in the another process ?? this is already enough for crash error. what is in ThreadProc not visible, but i not sure that it have no relocs. really ThreadProc must be member function of MB_DATA and access only it members. from you post obviously that you not debug remote process at injection time. also obviously that task is over your current level

Detours: Prevent task kill of my software via another software

I have found a code that promises to intercept and detour calls to the TerminateProcess function and thus prevent my software from being killed directly from other program.
But this code is not working and I am still able to kill my process via other program.
Here is the last my attempt with a code I have found in this YouTube video:
PS: victim.exe is the killer program.
DLL
// DllRedirectAPI.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include <Windows.h>
BYTE MOV[10] = { 0x48, 0xB8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
BYTE JMP_RAX[2] = { 0xFF, 0xE0 };
#define BuffSizeX64 (sizeof(MOV) + sizeof(JMP_RAX))
BOOL Hook_Det_x64(char LibName[], char API_Name[], LPVOID NewFun) {
DWORD OldProtect;
DWORD64 OrgAddress = (DWORD64)GetProcAddress(LoadLibraryA(LibName), API_Name);
if (OrgAddress == NULL) return 0;
memcpy(&MOV[2], &NewFun, 8);
VirtualProtect((LPVOID)OrgAddress, BuffSizeX64, PAGE_EXECUTE_READWRITE, &OldProtect);
memcpy((LPVOID)OrgAddress, MOV, sizeof(MOV));
memcpy((LPVOID)(OrgAddress + sizeof(MOV)), JMP_RAX, sizeof(JMP_RAX));
VirtualProtect((LPVOID)OrgAddress, BuffSizeX64, OldProtect, &OldProtect);
return 1;
}
int WINAPI MessageBoxAX(
HWND hWnd,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType) {
MessageBoxExA(0, "Hooked ...", "Mahmoud", 0, 0);
return 999;
}
BOOL WINAPI DllMain(HMODULE hModule, DWORD Call_Reason, LPVOID lpReserved) {
switch (Call_Reason) {
case DLL_PROCESS_ATTACH:
Hook_Det_x64("Kernel32.dll", "TerminateProcess", MessageBoxAX);
}
return 1;
}
INJECTOR
// Injector.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#include <conio.h>
#include <stdio.h>
#include <comdef.h>
#define WIN32_LEAN_AND_MEAN
#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)
BOOL Inject(DWORD pID, const char * DLL_NAME);
DWORD GetTargetThreadIDFromProcName(const char * ProcName);
int main(int argc, char * argv[])
{
//############### CHANGE HERE ONLY ###################
char *Target_Process = "victim.exe"; //###
//#######################################################
char *buf;
DWORD pID = GetTargetThreadIDFromProcName(Target_Process);
buf = "DllRedirectAPI.dll";
if (!Inject(pID, buf))
{
printf("DLL Not Loaded!");
}
else{
printf("DLL is Injected in torget Process");
}
_getch();
return 0;
}
BOOL Inject(DWORD pID, const char * DLL_NAME)
{
HANDLE Proc;
char buf[50] = { 0 };
LPVOID RemoteString, LoadLibAddy;
if (!pID)
return false;
Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
if (!Proc)
{
sprintf_s(buf, "OpenProcess() failed: %d", GetLastError());
printf(buf);
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "LoadLibraryA");
RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(Proc, (LPVOID)RemoteString, DLL_NAME, strlen(DLL_NAME), NULL);
CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
CloseHandle(Proc);
return true;
}
DWORD GetTargetThreadIDFromProcName(const char * ProcName)
{
PROCESSENTRY32 pe;
HANDLE thSnapShot;
BOOL retval, ProcFound = false;
thSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (thSnapShot == INVALID_HANDLE_VALUE)
{
printf("Error: Unable create toolhelp snapshot!");
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapShot, &pe);
while (retval)
{
if (_bstr_t(pe.szExeFile) == _bstr_t(ProcName))
{
return pe.th32ProcessID;
}
retval = Process32Next(thSnapShot, &pe);
}
return 0;
}
Can someone help me, telling me where I'm making a mistake?
My system is Windows 7 Ultimate 64 Bits.
Thanks in advance.
(Wanted to write a comment, but it got quite long...)
As #AndrewMedico says in the comment: You need to hook the TerminateProcess of the Task Manager process to prevent the Task Manager from terminating anything.
I suggest you the following approach:
Try a simple DLL injection
a/ Make a DLL which prints some text in its DllMain, e.g. printf("I am here\n"); fflush(stdout);
b/ Try to inject it into some other command line process using the process hacker's Miscellaneous>Inject DLL...
c/ Verify your DLL was executed inside the target process by checking it's standard output
Try a simple API hook:
a/ Make a command line application which waits for a key and then terminates itself using some variant of TerminateProcess(GetCurrentProcess(), 1);. Add code to print some text after the TerminateProcess call.
b/ Run this application to verify the text after calling the TerminateProcess is not printed.
c/ Hook the TerminateProcess before waiting for the key using, e.g. mhook. Print some text in the replacement function and then return. Do not call the original TerminateProcess here.
d/ Run this application to verify the text inside the hook is printed and the text after the TerminateProcess call is printed as well (i.e. verify the process termination was suppressed).
Combine the results of previous steps to reach your goal:
a/ Put the hooking code from from step 2 into the DLL from step 1
b/ Inject it into the application from step 2b (i.e. the one without the hook) while it is waiting for the key and verify the text after TerminateProcess is printed.
c/ Enjoy (or debug/blame me)
Good luck!
EDIT>
OK, here is my view of what we have here:
Code in the question:
(Is an application very similar to what I suggest in "2b")
Hooks the TerminateProcess and shows a message box instead.
Should display a message box when executed
(Looks like it is a 32-bit only version)
YouTube video
Shows an application "Terminate process.exe" which terminates process given by name
After the "Injector.exe" is executed the application ceases to terminate the process and displays a message box instead (IMHO the "Injector.exe" injects a "DllFile.dll" into the running "Terminate process.exe")
Source code for the injector in the YouTube comments
This code injects DLL "C:\DllRedirectAPI.dll" into the first process with name "victim.exe" it finds
(It does not inject into "Terminate process.exe", it does not use "DllFile.dll")
Source code for the DLL in the YouTube comments
This code hooks function MessageBoxA that it shows a different message box instead. It is worth noting that the hook code itself calls the original MessageBoxA and takes the approach that it reverts the modification it did during the hooking, calls the original function and then re-applies the hook.
(It does not hook 'TerminateProcess' at all)
(Looks like it is a 32-bit only version)
64-bit version excerpts
Destructive hook of MessageBoxA (i.e. does not backup the original code)
The hook uses MessageBoxExA (which is intact) to display a different message box instead (i.e. it does not use the overwritten MessageBoxA)
(It does not hook 'TerminateProcess' at all)
(It is a 64-bit version)
Disclaimer: I am not that proficient with the topic to be 100% sure, feel free to correct/clarify me.
For the actual hooking I personally recommend to use the mhook library, which worked for me. It's documentation is worth reading as well.
See e.g. this for some alternatives (I have not tried any of them)...
EDIT>
This one works for me on Win XP inside VirtualBox:
#include <windows.h>
#include <stdio.h>
#include <mhook.h>
static BOOL WINAPI
(*_TerminateProcess)(
_In_ HANDLE hProcess,
_In_ UINT uExitCode
) = NULL;
BOOL WINAPI
TerminateProcessImpl(
_In_ HANDLE hProcess,
_In_ UINT uExitCode) {
printf("\nBlocked\n"); fflush(stdout);
return 0;
}
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD Reason, LPVOID Reserved) {
if(Reason==DLL_PROCESS_ATTACH) {
printf("\nDLL attached!\n"); fflush(stdout);
HMODULE h = LoadLibrary("Kernel32");
if(h!=NULL) {
printf("\nGot Kernel32!\n"); fflush(stdout);
_TerminateProcess=(void*)GetProcAddress(h,"TerminateProcess");
if(_TerminateProcess!=NULL) {
printf("\nAbout to hook...\n"); fflush(stdout);
if(Mhook_SetHook((void*)&_TerminateProcess, &TerminateProcessImpl)) {
printf("\nHooked OK!\n"); fflush(stdout);
} else {
printf("\nHook failed!\n"); fflush(stdout);
}
}
}
}
return TRUE;
}

Get machine name from registry using RegQueryValueEx

I am trying to do an application which shows machine name of the PC fetch from registry. It has to run in 64 bit window 7 machine.
But I can only manage to output the system error message.
In below code,
I always get value of value1str (using RegOpenKeyEx method) => as 0 (which is ERROR_SUCCESS)
and value2str (using RegQueryValueEx method) => as 2 (which is ERROR_FILE_NOT_FOUND)
Anyone knows how to display the real machine name?
Please help!
#define KEY_WOW64_64KEY (0x0100)
#include <iostream>
#include <string>
BEGIN_MESSAGE_MAP(CPOConLogApp, CWinApp)
END_MESSAGE_MAP()
CPOConLogApp::CPOConLogApp()
{
int value1;
int value2;
HKEY root = NULL;
CString value1Str,value2Str;
value1=RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName"), NULL, KEY_READ|KEY_WOW64_64KEY, &root);
value1Str.Format("%d",value1);
MessageBoxA ( NULL, value1Str, "Test", MB_OK );
LPBYTE data = NULL;
DWORD dwType;
DWORD dwSize;
data = new BYTE[dwType];
value2=RegQueryValueEx(HKEY_LOCAL_MACHINE,TEXT("Computer Name"), NULL, &dwType, data, &dwSize);
value2Str.Format("%d",value2);
MessageBoxA (NULL, value2Str , "Test", MB_OK );
}
Alternative solution:
Instead of trying to find where is the key in the Registry and how to read it, you can just rely on the API Microsoft provide.
To get the Computer NetBIOS name (initialized from registry at system startup) use GetComputerName like below.
#include <windows.h>
int main()
{
char buf[1024];
DWORD dwCompNameLen = 1024;
if (0 != GetComputerName(buf, &dwCompNameLen)) {
printf("name %s\n", buf);
}
return 0;
}
You can read the computer name from the below mentioned registry key,
System\CurrentControlSet\Control\ComputerName\ComputerName
I found out why always ERROR_FILE_NOT_FOUND value. I suppose to put last parameter of RegOpenKeyEx to the first parameter in RegQueryValueEx. It should be like this.
value2=RegQueryValueEx(root,TEXT("Computer Name"), NULL, &dwType, data, &dwSize);
If you want prompts the value of the registry, computer name in this case, use the below code.
value.Format("%s",pszBuffer);
MessageBoxA (NULL, value , "Test", MB_OK );