For whatever reason in the following function, when it returns its telling me it failed to free the Allocated memory and GetLastError(): 5. If anybody has any insight into the issue it would be greatly appreciated. If you also have a better method of passing the data into an injected dll please let me know!
Code:
bool callFunction (char * functionName, char * format, ...) {
// Used for building code reference
BYTE codeFormat[] = "\xE8\x01\x00\x00\x00" // call codeStart;
"\xC3" // ret (returnAddress)
// codeStart :
"\xB8\x00\x00\x00\x00" // mov eax, functionAddress
//"\x68\x00\x00\x00\x00"// push arguments : will be increasing
// according to total arguments
// 11
"\xFF\xD0" // call eax (MessageBoxA) or the function called
"\x68\x00\x00\x00\x00" // push returnAddress
"\xC3"; // ret;
// Used to build the code
BYTE* codeBuild; // Stores the finished code
size_t codeLength = 0; // Calculate code total length
int codeAddLength = 0; // Calculate additional length like string length, etc
int codePos = 0; // The current position to insert byte;
int codeDataPos = 0; // The current position to insert data;
// Used to detect the arguments and build the code
va_list argumentsList;
char* strArgumentParsed; // Parse all string related arguments
int totalArguments = 0; // the total argument found. Used for calculating code length
// For finding all data about the function called by the user
DWORD functionAddress = 0;
// For code injection
BYTE* codeAlloc; // Will be used for the address to inject the finished code
HANDLE threadHandle = 0; // Handling the thread that will execute the code
DWORD threadExitCode = 0; // Stores the end of the thread
HINSTANCE hLibrary = LoadLibrary (dll.c_str());
if (!hLibrary) {
log._stream << "Attempted to load a dll but failed" << std::endl;
return false;
}
FARPROC pPrototype = GetProcAddress (hLibrary, functionName);
if (!pPrototype) {
log._stream << "Could not find function '" << functionName << "' in library - error code: " << GetLastError() << std::endl;
return false;
}
FARPROC pRelative = (FARPROC)((DWORD)pPrototype - (DWORD)hLibrary);
LPVOID pFunction = (LPVOID)((DWORD)pRelative + dwBaseAddress);
log._stream << "Attempting to call '" << functionName << "' at location:" << pFunction << std::endl;
// Check only if got anything in the format
if(format != "")
{
// Check the total arguments and calculate the total additional data size
va_start(argumentsList, format);
for(int i = 0; format[i] != '\0'; i++)
{
// Calculate the total arguments found
if(format[i] == '%')
{
totalArguments++;
i++;
}
// Calculate all the additional data size
switch(format[i])
{
case 'd':
case 'x':
// Skip because DWORD directly use the asm PUSH statement
va_arg(argumentsList, DWORD);
break;
case 's':
// Add the size of arguments to additional code length
codeAddLength += lstrlen(va_arg(argumentsList, char*)) + 1;
break;
}
}
va_end(argumentsList);
}
// Start building the code
codeLength = (totalArguments * 5) + sizeof(codeFormat) + codeAddLength;
codeBuild = new BYTE[codeLength];
// Initialize the position
codePos = 0;
codeDataPos = codeLength - codeAddLength - 1;
// Allocate memory address for code injection here since we are using it for building
// the code
//pRemote = VirtualAllocEx (hProcess, NULL, numBytes, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
codeAlloc = (BYTE*)VirtualAllocEx(hProcess, NULL, codeLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(!codeAlloc)
{
log._stream << "Failed to allocate memory address" << std::endl;
return false;
}
// Add the first 7 bytes from the code reference
for(int i = 0; i < 7; i++, codePos++)
codeBuild[codePos] = codeFormat[i];
//printf("\n\n %.02X \n\n", codePos);
// Skip the 7th byte and move to the next one
// codePos++;
// For the 8th byte to 11th byte, add the function address
*(DWORD*)&codeBuild[codePos] = functionAddress;
// Skip 4 bytes and move to the next one
codePos += 4;
//for(int i = 0; i < totalArguments * 5;i++, codePos++)
// codeBuild[codePos] = 0x00;
// Skip all the push statement and move to the next one
codePos += (totalArguments * 5);
// Again, add the next 3 bytes from the code reference
for(int i = 11; i < 14; i++, codePos++)
codeBuild[codePos] = codeFormat[i];
// Add the address of the ret to push statement
*(DWORD*)&codeBuild[codePos] = (DWORD)codeAlloc + 5;
// Skip 4 bytes and move to the next one
codePos += 4;
// Add the last 1 bytes from the code reference
//for(int i = 18; i < 20; i++, codePos++)
codeBuild[codePos] = codeFormat[18];
// Step backward 8 bytes to build all the push statement
// Since asm is backward ex: (..., arg3, arg2, arg1, arg0)function
// We should also going backwards
codePos -= 7;
if(format != "")
{
// Build all the push statements and also insert the arguments
va_start(argumentsList, format);
for(int i = 0; format[i] != '\0'; i++)
{
// This is to insert the push statement
codePos -= 5;
if(format[i] == '%')
{
// insert the push statement and skip 1 byte;
codeBuild[codePos] = 0x68;
codePos++;
// move to the character after %
i++;
switch(format[i])
{
case 'd':
case 'x':
// Add the DWORD into the code
*(DWORD*)&codeBuild[codePos] = va_arg(argumentsList, DWORD);
break;
case 's':
// Parse the string to our string parser
strArgumentParsed = va_arg(argumentsList, char*);
// Add the address of the string to the push statement
*(DWORD*)&codeBuild[codePos] = (DWORD)(codeAlloc + codeDataPos);
// For every character in the string add to the code in the data section
for(int j = 0; j < lstrlen(strArgumentParsed); j++, codeDataPos++)
codeBuild[codeDataPos] = strArgumentParsed[j];
// Add the next byte as the string ending
codeBuild[codeDataPos] = 0x00;
// Move the data position by 1 skipping the string end
codeDataPos++;
break;
}
// Move backwards 1 bytes to build the next push statement
codePos--;
}
}
va_end(argumentsList);
}
if(!WriteProcessMemory(hProcess, (LPVOID)codeAlloc, codeBuild, codeLength, NULL))
{
log._stream << "Failed to write process memory" << std::endl;
return false;
}
threadHandle = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)codeAlloc, 0, 0, NULL);
if(!threadHandle)
{
log._stream << "Failed to create remote thread" << std::endl;
return false;
}
if(WaitForMultipleObjects(1, &threadHandle, TRUE, 5000) != 0)
{
log._stream << "Failed on waiting \n" << std::endl;
return false;
}
if(!GetExitCodeThread(threadHandle, &threadExitCode))
{
log._stream << "Failed to retrieve thread exit code \n\n" << std::endl;
return false;
}
if (codeAlloc) {
if(!VirtualFreeEx(hProcess, codeAlloc, 0, MEM_RELEASE))
{
log._stream << "Failed to free virtual allocation. " << std::endl;
return false;
}
}
return true;
}
Exported Function
Code:
extern "C" __declspec (dllexport) DWORD __stdcall testFunction (char *s, int v) {
log_dll._stream << s << " " << v << std::endl;
return 1;
}
Called via
Code:
g_Manager.callFunction ("_testFunction@8", "%s%d", "test", 8);