How do you use SymLoadModuleEx to load a PDB file? - c

I'm trying to call SymLoadModuleEx to load the symbols from a PDB file and then use SymFromAddr to look up symbols from that PDB. However, I can't figure out what to pass for the parameters BaseOfDll and DllSize -- the documentation explicitly says that when loading a PDB file, these parameters can't be 0, and indeed attempting to pass 0 results in it failing with ERROR_INVALID_PARAMETER.
Here's what my code looks like:
SymSetOptions(SYMOPT_LOAD_LINES);
HANDLE hprocess = GetCurrentProcess();
if (!SymInitialize(hprocess, NULL, FALSE))
die("SymInitialize");
if(SymLoadModuleEx(hprocess, NULL, "full path to some PDB file.pdb", NULL,
0, // What to pass here?
0, // What to pass here?
NULL, 0) == 0)
{
die("SymLoadModuleEx");
}
How do you figure out what BaseOfDll and DllSize to pass in when loading a PDB file? The PDB file in question is the symbol file for a different program executable (not a DLL), and just for the sake of argument, assume that you don't have access to the original EXE from which the PDB was generated.
Alternatively, is there a better method of looking up the symbols corresponding to a given address from a PDB file?

dbghelp.dll and the Sym* methods here make use of the Debug Interface Access (DIA) SDK.1
DIA itself is COM-based and much more flexible than what DbgHelp offers.
Specifically, to load a known PDB and lookup a symbol based on an address, you can do the following:
CoCreate a DIA data source (see the "Example" section here).
Use IDiaDataSource::loadDataFromPdb to load a specific PDB (DLL size and base address are not needed).
Use IDiaDataSource::openSession to get the IDiaSession for your data source.
Depending on if you have an absolute virtual address (VA) or relative virtual address (RVA), you can use findSymbolByVA or findSymbolByRVA, respectively, to get the IDiaSymbol associated with that address.
Finally, you can use IDiaSymbol::get_name to get the function name containing the address you specified.
None of this requires the original image; only the PDB is required. Assuming you're using Visual Studio, the headers and libraries for DIA are available under (for example):
C:\Program Files (x86)\Microsoft Visual Studio 10.0\DIA SDK.

The Dia2Dump sample works well for me in resolving relative virtual address (eip-program load address) to pdb for unresolved function pointers. This is the way I try it:
DWORD64 dwAddress = _wcstoui64(argv[i], NULL, 16);
DWORD64 dwRVA = dwAddress - dwLoadAddress;
long displacement = 0;
IDiaSymbol* pFunc = 0;
error = (DWORD)g_pDiaSession->findSymbolByRVAEx(dwRVA, SymTagFunction, &pFunc, &displacement );
if (!error && pFunc)
{
BSTR bstrName;
if (pFunc->get_name(&bstrName) != S_OK) {
wprintf(L"(???)\n\n");
}
else {
wprintf(L"%s \n\n", bstrName);
if (displacement)
wprintf(L"+ 0x%x \n\n", displacement);
else
wprintf(L" \n\n");
SysFreeString(bstrName);
}
}
For example:
Function: [00447B60][0001:00446B60] ServerConfig::getSSLConfig(public: struct ssl_config __cdecl ServerConfig::getSSLConfig(void) __ptr64)
Here the RVA is 00447B60 [ eip - Process Load Address ]
the Segment is 0001
the offset is 00446B60

I don't have permitions to comment, so will do this in separate answer.
Yes, DbgHelp is a wrapper around DIA, only in terms of static lib. DIA is statically linked into DbgHelp.dll. DbgHelp directly calls Dia's COM class factory (IClassFactory) implementation bypassing COM. I'm talking about 6.1.7601.17514 version. So DbgHelp.dll is self-contained (in combination with symcrv.dll and srcsrv.dll)
Dia COM objects are shipped with Visual Studio (same location with dbgeng.dll), so solution we not work on envs where VS is not installed (but you still could try to use msdia120.dll as private assembly pointing to it via ActivateActCtx, but also need to deploy dependencies, if they present)
DbgHelp is compact and recommended to distribute private copies with your application by Microsoft. See "The redistribution policies for these included DLLs were specifically designed to make it as easy as possible for people to include these files in their own packages and release"
I didn't find the way how to download PDB files using DIA interfaces. Sym API allows this. it delegates calls to SymSrv.dll.
So original question is still actual.

Related

Setting a directory path to a dynamically linked library in an R package

What is the proper way to load in a dynamically linked library (i.e., a .so file) when writing an R package? The only solution that has worked for me so far has been to specify the full path to the .so file, e.g.:
dyn.load('/FULL/PATH/TO/MY/R_PACKAGE/src/my_file.so')
Obviously, this approach will not work for a CRAN/Bioconductor submission since the .so file will not be located. As such, I have (unsuccessfully) tried the following alternatives:
1) library.dynam()
2) library.dynam('my_file.so')
3) library.dynam('my_file.so', 'R_PACKAGE')
4) system.file("src", "my_file.so", package = "R_PACKAGE")
Related links: R: C symbol not in load table, R: C symbol name not in load table - error in linking with external .c files.
Just to be crystal clear, users of my R package may obviously set any arbitrary working directory on their computers. The only way a full path approach (as shown above) would ever work is if they set their working directory to /FULL/PATH/TO/MY/R_PACKAGE/src, which is (of course) impractical.
The standard way to do this, as described in Writing R Extensions, is:
1.5.4 useDynLib
A NAMESPACE file can contain one or more useDynLib directives which allows shared objects that need to be loaded.* The directive
useDynLib(foo)
registers the shared object foo** for loading with library.dynam. Loading of registered object(s) occurs after the package code has been loaded and before running the load hook function. Packages that would only need a load hook function to load a shared object can use the useDynLib directive instead.
* NB: this will only be read in all versions of R if the package contains R code in a R directory.
** Note that this is the basename of the shared object, and the appropriate extension (.so or .dll) will be added.
Quick points:
Why do you need to ship a .so file? This would preclude uploads to common repos like CRAN which will not accept binary content
You can compute the full /FULL/PATH/TO/MY/R_PACKAGE/src/my_file.so by using system.file("src", "my_file.so", package="R_PACKAGE") (but then make sure you actually install a src/ which is not standard)
In all other cases (as pointed out by #BenBolker) R will know how to create the dynamic library and load it for you. Every package with compiled code does that. Just drop your source code into src/ and you are (essentially) done.

STATUS_INVALID_IMAGE_HASH (0xc0000428) on valid PE files

I tried loading the DLL file "bcryptprimitives.dll" (which in my case, originally sits under "C:\Windows\syswow64\bcryptprimitives.dll") from another location, with this snippet of code:
LoadLibraryW(L"<altered path>\\bcryptprimitives.dll");
However, right after executing this line of code I get the following error:
C:\Program Files (x86)\Notepad++\bcryptprimitives.dll is either not designed to run on Windows or it contains an error. Try installing the program again using the original installation media or contact your system administrator or the software vendor for support. Error status 0xc0000428.
I searched the 0xc0000428 NTSTATUS in the following dictionary: https://msdn.microsoft.com/en-us/library/cc704588.aspx
and apparently this status means STATUS_INVALID_IMAGE_HASH.
The error at first makes sense, because I changed the "LoaderFlags" field in the image PE header from 0x00000000 to 0x00000001 (which doesn't need to affect anything because this field is deprecated), but even though I changed the field, I fixed the PE checksum.
As you can see:
However, LoadLibrary still refuses to load the DLL.
Diving deep into ntdll reveals that the error is returned from kernel:
It makes me think that the DLL is somehow signed and the kernel checks whether the DLL was altered.
So to my point, how can I load this DLL from another location anyway and remove the sign check?
If a DLL is signed, then by changing a single byte in the file will invalidate the signature. It appears you are doing exactly that by modifying PE header.
This blog post might be of interest to for deeper insight how this technology works:
Code Integrity is a feature that improves the security of the operating system by validating the integrity of a driver or system file each time it is loaded into memory. Code Integrity detects whether an unsigned driver or system file is being loaded into the kernel, or whether a system file has been modified by malicious software that is being run by a user account with administrative permissions. On x64-based versions of the operating system, kernel-mode drivers must be digitally signed.
Found a quick solution:
DWORD dwIndex = 0;
hFile = CreateFileW(L"C:\\Program Files (x86)\\Notepad++\\bcryptprimitives.dll", FILE_READ_DATA | FILE_WRITE_DATA, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
while (ImageRemoveCertificate(hFile, dwIndex))
{
++dwIndex;
}
LoadLibraryW(L"C:\\Program Files (x86)\\Notepad++\\bcryptprimitives.dll");
It is working like a charm :)
This is how the API works:
Calculate the offset of the end of the last section.
Remove all the data following that section.
Remove the security data directory.
Shrink the image.
Calculate an updated checksum of the PE.

Axis2 fails to load DLL

I came across the below line in the Apache-Axis2 log file.
[Sat Nov 14 12:16:08 2015] [error] ..\..\util\src\class_loader.c(167) Loading shared library ..//lib/axis2_http_sender.dll Failed. DLERROR IS DLL Load Error 126: The specified module could not be found.
On analyzing the class_loader.c file from line#156 to line#167 as given below:
dll_name = axutil_dll_desc_get_name(dll_desc, env);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Shared library to be loaded is %s",dll_name);
dl_handler = AXIS2_PLATFORM_LOADLIB(dll_name);
if (!dl_handler)
{
#ifndef WIN32
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Loading shared library %s Failed. DLERROR IS %s",
dll_name, AXIS2_PLATFORM_LOADLIB_ERROR);
#else
axis2_char_t buff[AXUTIL_WIN32_ERROR_BUFSIZE];
axutil_win32_get_last_error(buff, AXUTIL_WIN32_ERROR_BUFSIZE);
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "Loading shared library %s Failed. DLERROR IS %s",dll_name, buff);
I guess the problem is in the very first line - dll_name = axutil_dll_desc_get_name(dll_desc, env);. The value stored in dll_name is ..//lib/axis2_http_sender.dll. Though the axis2_http_sender.dll is present
in the lib directory which is relative to the executable, the linker fails to connect to it.
I have never seen file name syntax like below:
..//lib/axis2_http_sender.dll
I tested it in Windows Command line and it worked like :
../lib/axis2_http_sender.dll
What are the implication of using consecutive /s in a C
function like fopen()?
I did try few code samples.
Below is a piece of C code:
FILE *fp;
fopen_s(&fp,"C://tempfile.txt", "w");
fputs("Text content", fp);
fclose(fp);
The above code worked fine for me.
Cracked this one finally.
This CSDN blog post suggested that Axis2C Windows distribution depends on OpenSSL DLLs.
I listed the dll dependencies of axis2_apache_server.exe using the following command.
listdlls axis2_apache_server.exe
and the list showed that the two ssl dlls libeay32 and ssleay32 are required to run it. However, these two dlls were missing from the Axis2 Binary Distribution.
(I don't know why & I think it should have been included. Moreover there is no mention of this in Axis2 documentation.)
The above dlls are available in either Apache2 or OpenSSL installs the I added the path to these dlls to my PATH variable.
I ran the axis2_apache_server.exe and voila !!
Conclusion:Consecutive /s in the file path doesn't affect the linking at all.
Moral: One should check the dll dependencies of an exe file first and make sure that all the dlls are present when he ran into a dll load error.
Hard learned moral though!!

to make a self-contained exe that extracts files and other commands

I am making a filtering sniffer in C and winPCAP that starts on every boot. For this I want to make a self-contained exe file that extracts (no, not compression!) the exe and DLLs to a new folder and performs other commands (like modify startup settings) silently, without showing any window/terminal.
So
The single file contains an exe and DLLs.
When executed, it copies the files to a folder and does other commands
It does it silently, without any windows or terminals or user intervention
I stress on the silent part, so I cant choose some easy installers. Can you reccomend something that generates this executable?
For the curious: its a stealth packet logger program for my college project. The "stealth" part will be tried out only on xp2 virtual machines with IE6 (yeah, old stuff).
EDIT: answering the commenters: it is of a malware character. So I am running it in virtualbox, never on the loose. And I can compromise only an unpatched xp systems with IE6, without antivirus, that is from an OLD install disk. Thats the scope of the IE css use after free vulnerability, AFAIK never seen in the wild. So there is no unethical behavior involved.
You can easily embed resources either by linking them in, with the compiler, or by using a special program and instrumenting the windows API.
Something along the lines of :
char file_to_be_altered[] = "MyInstaller.exe"
HANDLE hUpdate = BeginUpdateResource( file_to_be_altered, FALSE );
UpdateResource( hUpdate, "MyResType", "MyResName1", 0, pData, data_len );
EndUpdateResource( hUpdate, FALSE );
Then when your executable runs, you enumerate your resources and select those that have the type "MyResType".
struct res_entry { BYTE* pData; unsigned int len; }
BOOL CALLBACK EnumNamesCB(
HMODULE hModule, // module handle
LPCTSTR lpType, // address of resource type
LPTSTR lpName, // address of resource name
LONG_PTR lParam) //
{
std::vector<res_entry>& lst = *(reinterpret_cast< std::vector<res_entry>* >( lParam ));
HRSRC hRes = FindResource( hModule, lpName, lpType );
if( hRes == 0 ) return TRUE;
unsigned int len = SizeofResource( hModule, hRes );
HGLOBAL hGlob = LoadResource( hModule, hRes );
if( hGlob == 0 ) return TRUE;
res_entry t;
t.pData = LockResource( hGlob );
t.len = len;
lst.push_back( t ); // this is safe, because the resources are never deallocated
return TRUE;
}
....
void enum_entries()
{
std::vector<res_entry> lst;
::EnumResourceNames( hFileToQuery, "MyResType", &EnumNamesCB, reinterpret_cast<LONG_PTR>(&lst) );
}
You can do whatever you want with this data, e.g. CreateFile ... and the write the data out to disc.
NB: This is how installers may do it on windows, and this was developed to extract files to the temp dir and install from there.
The trivial way to do it is to create a very large array inside your program, and store the data to be extracted inside that array. When executed the program takes the array and writes it out to a file or files as needed, then executes the file you want to run once the files are extracted. See, for example, C Question: How to store data inside the executable file.
Once the program is compiled you can replace the data in the EXE using a binary editor to copy your files in place without having to convert your files to a C array or some other data structure every time you change your payload.
In order to keep the size down the primary program typically decompresses the array and expects a compressed array. A lot of installers simply use zip as the decompressor takes care of multiple files in one array, and you don't have to fiddle with adding a directory array and reference array - it's all built in, and command line zip compressors are common and easy to use.
Whether the primary program opens a terminal depends on how you program it. I expect you'll need it to be a win32 program so windows doesn't open a DOS terminal, and you simply don't open any windows inside your program. That's a separate question, though, so consider asking it as a new question.
As David points out, this process is typically automated in the linker stage. Each linker is slightly different, but you can check out Embedding resources in .exe using GCC for an example using one of the more common compilers.
I assume you know what you are doing, but keep in mind that there are a lot of unpatched stock winxp sp2 systems out there - assuming that you won't hurt anyone because you don't believe such systems are online is a poor choice. Make certain that your program doesn't have the ability to leave the virtual machines. There are ways, for instance to connect their networks without allowing the machines access to the internet, or your computer's network. Keep in mind that the Morris worm was a pet project that wasn't intended or expected to go wild either.

Recommended way to load .so package in tcl either statically or dynamically

I've an executable hosting tcl interpretor, and a library hosting a extension.
I want to be able to build the library dynamically (loaded with Tcl's load)
or statically (single executable, or so loaded implicitly).
The Executable code:
#ifdef GO_STATIC
extern int My_ext_Init(Tcl_Interp* interp);
Tcl_StaticPackage(interp, "my_ext", My_ext_Init, My_ext_Init);
My_ext_Init(interp); // THIS SHOULD NOT BE NEEDED !!
Tcl_SetVariable(interp, "is_statically_linked", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVariable(interp, "is_statically_linked", "0", TCL_GLOBAL_ONLY);
#endif
The library Code .. can be static or dynamic library ( .a or .so / .lib or .dll ):
int My_ext_Init(Tcl_Interp *interp)
{
if (Tcl_PkgProvide(interp, "My_ext", "1.0") == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp, /*...etc...*/);
}
The startup tcl code:
global is_statically_linked
if {$is_statically_linked} {
load {} my_ext
} else {
load my_ext my_ext
}
The problem is .. I really shouldn't be calling My_ext_Init(interp); as it
should called by Tcl when I evaluate load {} my_ext
Made community wiki so that the recommended way can be put here.
Registering a “static package” is done in your application init routine, and should be done after the main interpreter is created (but obviously before you start running your scripts in it). It's a mechanism that's really designed to work the “Big Wish” method of program building, when you use Tcl_Main() to do the work of making an interpreter. When you're doing that, there's a callback into your code (typically called Tcl_AppInit though the name is actually arbitrary) that you can specify and which is the ideal place to put calls to Tcl_StaticPackage. The callback will be called at the right point for you to do the static package registration.
However, that's all considered rather old hat these days. A far better method is to always use dynamic libraries and to instead package everything together as a starkit or starpack. The advantage with doing that is that you just need to build your .so files as stub-enabled (strongly recommended anyway) packages and then you include them in your VFS during the packaging process. After that, you can just do package require and it will all work. (Or you can locate the shared libraries in the virtual mount when running and load them directly.) What's even better is that you can deliver a single .kit file that supports multiple platforms; starpacked executables can't be quite that flexible though, as there are some natural restrictions on portability of binary executables. :-)

Resources