I'm trying to implement a debugger like capability (Windows 10). I have a C program in my DLL, then a want to execute this program through an exe file which instantiate this DLL.
I'm able to manipulate variable/functions exposed with __declspec( dllexport )
but I want to do the same with global (or any?) variable.
First, I can see my variable with objdump -t
command:
[3400](sec 4)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x000000a1 ___notExportedVar
here is the sample of my code:
void getVariable(void* inst, const char* function)
{
HINSTANCE handle = (HINSTANCE) inst;
ULONG64 buffer[(sizeof(SYMBOL_INFO) +
MAX_SYM_NAME * sizeof(TCHAR) +
sizeof(ULONG64) - 1) /
sizeof(ULONG64)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
TCHAR szSymbolName[MAX_SYM_NAME];
_tcscpy_s(szSymbolName, MAX_SYM_NAME, TEXT(function));
BOOL status;
SymSetOptions(SYMOPT_UNDNAME|SYMOPT_DEBUG|SYMOPT_DEFERRED_LOADS|SYMOPT_PUBLICS_ONLY);
//
// Set _NT_SYMBOL_PATH for the current process
//
SetEnvironmentVariable("_NT_SYMBOLS_PATH", "E:\\path\\to\\exe;E:\\path\\to\\dll;SRV*C:\\WINDOWS\\TEMP*http://msdl.microsoft.com/download/symbols");
//status = SymInitialize(handle, NULL, FALSE);
status = SymInitialize(handle, NULL, TRUE);
if (status == FALSE)
{
DWORD lastError = GetLastError();
error(INTERNAL_ERROR, "ERROR: SymInitialize - Windows Error %d - see https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-", lastError);
}
if (SymFromName(handle, szSymbolName, pSymbol)){
//do stuff here
}else{
DWORD err = GetLastError();
error(INTERNAL_ERROR, "ERROR: unable to find %s variable in DLL - Windows Error %d - see https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-", function, err);
}
}
Running above code exit with windows error code: 3221225485 as result of status = SymInitialize(handle, NULL, TRUE);
using FALSE as 3rd argument makes the program fails at SymFromName(handle, szSymbolName, pSymbol)
with error 126
Note: the handle I gave is the one I observe for my DLL in processExplorer.
First problem is that HINSTANCE is not a process handle.
You want to pass in a process handle returned from Process32First/Process32Next query.
For your own process you can call GetCurrentProcess to get the current process id. The problem is that you run in this problem if you use your own process handle:
SymInitialize function
So you can't really debug your own process, which is what you are actually trying to do.
If you only want to lookup a symbol, you don't need to debug your own application. What you can do is setup a fake process, load the symbol information for a module (e.g. your exe) (SymLoadModuleEx) and then lookup the symbol.
Most people just use the constant process handle of '1' for the fake process id. For fake processes you must pass 'FALSE' for the fInvadeProcess parameter.
That can be done from any program at any time. But you will not get the "address" of the global variable as you need the loaded module address (which is randomized nowadays - basically the HINSTANCE of the module the symbol comes from of a running process).
If you actually want to get actual live address, you need to change the call to SymLoadModule to pass the hinstance value of the the module.
To be generic, you can use GetModuleFileName to get the module image name from the hinstance (hinstance == hmodule these days). You can use the returned value to pass into SymLoadModuleEx ImageName parameter.