AceInfinity
Emeritus, Contributor
Here's a test I put together for calling to load a dll from a process of choice.
Simple Summary: Basically what this does is it calls to inject into the specified process to call a dll which when loaded calls to the Windows API, the GetCommandLine() function which is provided as a parameter to the popular MessageBox() function to be shown to the end user. I've learned a lot about specific flags that certain program's use on my system by testing a few different processes out.
The idea is relatively simple, first calling OpenProcess to get a handle to the specified process. We also get the address of the function LoadLibraryA (ANSI) from kernel32.dll. Next, I make sure that we have memory allocated inside the process' address space so that we can do stuff with this reserved memory. The WriteProcessMemory function is called to write to this newly allocated memory, with the location of the dll to be loaded. Lastly, calling CreateRemoteThread to create a new thread within that process which calls LoadLibraryA() with the address of the returned memory space from VirtualAllocEx, which we used previously to write the location of the dll to.
Our dll just calls the Windows MessageBox() function from the Windows API with GetCommandLine() as one of its parameters.
Result:
Simple DLL:
Main:
Perhaps more argument handling could be added, but this was just a simple test anyways.
Simple Summary: Basically what this does is it calls to inject into the specified process to call a dll which when loaded calls to the Windows API, the GetCommandLine() function which is provided as a parameter to the popular MessageBox() function to be shown to the end user. I've learned a lot about specific flags that certain program's use on my system by testing a few different processes out.
The idea is relatively simple, first calling OpenProcess to get a handle to the specified process. We also get the address of the function LoadLibraryA (ANSI) from kernel32.dll. Next, I make sure that we have memory allocated inside the process' address space so that we can do stuff with this reserved memory. The WriteProcessMemory function is called to write to this newly allocated memory, with the location of the dll to be loaded. Lastly, calling CreateRemoteThread to create a new thread within that process which calls LoadLibraryA() with the address of the returned memory space from VirtualAllocEx, which we used previously to write the location of the dll to.
Our dll just calls the Windows MessageBox() function from the Windows API with GetCommandLine() as one of its parameters.
Result:
Simple DLL:
Code:
[NO-PARSE]#include <stdio.h>
#include <Windows.h>
BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved)
{
switch (reason) {
case DLL_PROCESS_ATTACH:
MessageBox(NULL, GetCommandLine(), "Command Line", MB_OK);
break;
}
return TRUE;
}[/NO-PARSE]
Main:
Code:
[NO-PARSE]#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
void display_usage(const char *arg0)
{
const char *ptr_slash = strchr(arg0, '\\');
const char *bin = ptr_slash == NULL ? arg0 : strrchr(arg0, '\\') + 1;
printf(
"Usage: %s [DLLFile] [ProcessID]\n"
"Example: %s \"C:\\drivers\\mydll.dll\" 1427\n"
, bin, bin);
}
int main(int argc, char const *argv[])
{
// Check argument count
if (argc < 3) {
display_usage(argv[0]);
return 0;
}
// Parse PID argument
int process_id = strtol(argv[2], 0, 10);
if (process_id == 0) {
fprintf(stderr, "Error: the specified process ID was invalid.\n");
return 1;
}
const char *dll_path = argv[1];
// Retrieve process handle from PID
HANDLE p_handle = OpenProcess(
PROCESS_ALL_ACCESS, // Requested access level
FALSE, // Inherit handle
process_id // Process ID of process to open
);
if (p_handle == NULL) {
fprintf(stderr, "Error: the specified process couldn't be found.\n");
return 1;
}
// Get the address of the LoadLibrary function (ANSI/Non-Unicode alias)
LPVOID addr = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if (addr == NULL) {
fprintf(stderr, "Error: the LoadLibraryA function was not found inside kernel32.dll library.\n");
return 1;
}
// Allocate a new memory region inside the process' address space
LPVOID arg = (LPVOID)VirtualAllocEx(p_handle, // Process handle
NULL, // Start address for allocation region
strlen(dll_path), // Size of region to allocate
MEM_RESERVE | MEM_COMMIT, // Allocation type flags
PAGE_READWRITE // Memory protection
);
if (arg == NULL) {
fprintf(stderr, "Error: the memory could not be allocated inside the chosen process.\n");
return 1;
}
// Write the dll filepath to the memory space allocated from the call to VirtualAllocEx()
// This is the argument for the LoadLibraryA() call
int n = WriteProcessMemory(p_handle, // Process handle
arg, // Base address to write to
dll_path, // dll_path
strlen(dll_path), // dll_path length
NULL // Number of bytes written
);
if (n == 0) {
fprintf(stderr, "Error: there was no bytes written to the process's address space.\n");
return 1;
}
// Inject the DLL into the specified process' address space
DWORD thread_id = 0;
HANDLE threadID = CreateRemoteThread(p_handle, // Process handle
NULL, // Security descriptor
0, // Initial stack size (bytes)
(LPTHREAD_START_ROUTINE)addr, // Function address
arg, // Function variable
0, // Creation flags
&thread_id // Thread identifier variable
);
if (threadID == NULL) {
fprintf(stderr, "Error: the remote thread could not be created.\n");
return 1;
}
printf(
"DLL File: %s\n"
"Process ID: %d\n"
"Success: Remote thread was successfully created."
"\n\tThread ID = %d\n"
, dll_path, process_id, thread_id);
// Close the handle to the process
CloseHandle(p_handle);
}[/NO-PARSE]
Perhaps more argument handling could be added, but this was just a simple test anyways.
Last edited: