I tried to test the RegCreateKeyEx call using asm inline.
This is the code :
long regkey(HKEY lnKey, LPCTSTR lpsub, DWORD rise, LPTSTR lpc, DWORD dwopt, REGSAM sd, LPSECURITY_ATTRIBUTES lpas, HKEY * const &llkey, DWORD * const &dwDisposition)
{
__asm
{
lea eax, dwDisposition
push eax // put eax at the top of the stack
lea eax, llkey
push eax
lea eax, lpas
push eax
lea eax, sd
push eax
lea eax, dwopt
push eax
lea eax, lpc
push eax
lea eax, rise
push eax
lea eax, lpsub
push eax
lea eax, lnKey
push eax
call DWORD ptr RegCreateKeyEx
}
return;
}
int main()
{
HKEY lnKey;
LPCTSTR lpsub;
DWORD rise;
LPTSTR lpc;
DWORD dwopt;
REGSAM sd;
LPSECURITY_ATTRIBUTES lpas;
HKEY llkey;
DWORD dwDisposition;
long ret0 = regkey(HKEY_CURRENT_USER, TEXT(linkey.c_str()), 0, NULL, 0, KEY_WRITE, NULL, &llkey, &dwDisposition);
printf("CREATE %d\n", ret0);
return 0;
}
However, it returns error 87 (INVALID ARGUMENT).
The linkey.c_str () variable contains the string "Software\\Microsoft\\Windows\\CurrentVersion\\Run\\" path and passes it correctly because I tried to use it directly by calling directly the RegCreateKeyEx (HKEY_CURRENT_USER,
TEXT (linkey.c_str ()),
0, NULL, 0,
KEY_WRITE, NULL,
& Llkey, & dwDisposition) ad it's all OK
Where am I wrong in use asm inline?
If you wrote the code in C++, like so:
LONG regkey(HKEY lnKey, LPCTSTR lpsub, DWORD rise, LPTSTR lpc, DWORD dwopt, REGSAM sd, LPSECURITY_ATTRIBUTES lpas, HKEY * const &llkey, DWORD * const &dwDisposition)
{
return RegCreateKeyEx(lnKey, lpsub, rise, lpc, dwopt, sd, lpas, llkey, dwDisposition);
}
then you could compile it using the /FA switch, as advised in the comments, to get the compiler to generate an assembly listing of the code it would generate. Alternatively, you could compile it and then break in, using the debugger to show the disassembly of the actual binary. Either way, you'd see the following assembly code being generated by the compiler:
mov eax, DWORD PTR [esp+36] ; dwDisposition
push DWORD PTR [eax]
mov eax, DWORD PTR [esp+36] ; llkey
push DWORD PTR [eax]
push DWORD PTR [esp+36] ; lpas
push DWORD PTR [esp+36] ; sd
push DWORD PTR [esp+36] ; dwopt
push DWORD PTR [esp+36] ; lpc
push DWORD PTR [esp+36] ; rise
push DWORD PTR [esp+36] ; lpsub
push DWORD PTR [esp+36] ; lnKey
call DWORD PTR RegCreateKeyEx
ret 0
So, the inline assembly should be:
LONG regkey(HKEY lnKey, LPCTSTR lpsub, DWORD rise, LPTSTR lpc, DWORD dwopt, REGSAM sd, LPSECURITY_ATTRIBUTES lpas, HKEY * const &llkey, DWORD * const &dwDisposition)
{
__asm
{
mov eax, DWORD PTR [dwDisposition]
push DWORD PTR [eax]
mov eax, DWORD PTR [llkey]
push DWORD PTR [eax]
push DWORD PTR [lpas];
push DWORD PTR [sd];
push DWORD PTR [dwopt];
push DWORD PTR [lpc];
push DWORD PTR [rise];
push DWORD PTR [lpsub]
push DWORD PTR [lnKey]
call DWORD PTR RegCreateKeyEx
} // return value is left in EAX
}
which is pretty darn easy. You don't need to worry about calculating offsets from the stack pointer, because the inline assembler supports the use of C++ variables. There is never a need for a LEA instruction. In fact, the LEA instruction is wrong, because it causes you to pass pointers as parameters to the RegCreateKeyEx function, instead of the values themselves, which is why you were getting error code 87, "Invalid parameter".
The only complicated thing is the way the dwDisposition and llkey parameters are handled. First, the address has to be loaded into a register (EAX), and then that address is dereferenced as it is pushed onto the stack. This additional level of indirection is necessary because you passed these parameters as references to pointers. I have no idea why you've chosen to do that, but because you did, the reference has to be dereferenced. (Under the hood, a C++ compiler implements references like pointers.)
However, I have no idea why you would actually write this code in inline assembly. There is absolutely no reason to do so; it isn't buying you anything, it's just making things more complicated to write and maintain. It's also costing you something in performance. Above, I showed what a C++ compiler would generate for the function call. Here is what the compiler generates when you use inline assembly:
push ebp
mov ebp, esp
mov eax, DWORD PTR _dwDisposition$[ebp]
push DWORD PTR [eax]
mov eax, DWORD PTR _llkey$[ebp]
push DWORD PTR [eax]
push DWORD PTR _lpas$[ebp]
push DWORD PTR _sd$[ebp]
push DWORD PTR _dwopt$[ebp]
push DWORD PTR _lpc$[ebp]
push DWORD PTR _rise$[ebp]
push DWORD PTR _lpsub$[ebp]
push DWORD PTR _lnKey$[ebp]
call DWORD PTR RegCreateKey
pop ebp
ret 0
Notice the extra prologue and epilogue instructions that are made necessary by the use of inline assembly, since the compiler has no idea what you are actually doing inside of the inline assembly and therefore has to compensate for it by setting up and tearing down a stack frame. It isn't a massive performance cost or anything, but again, it's completely pointless.
Your follow-up question/problem (from a comment and an answer you posted) makes no sense to me. You shouldn't need any sort of exception handler, and since you didn't quote the exact error message you're getting, I have no idea what it might be trying to say. It is likely that the problem relates to strtemp, whose declaration you don't show us. Since you said you are calling the ANSI version of RegCreateKeyEx, strtemp should be a pointer to a char buffer, terminated with a NUL character. Also, the next parameter you are passing to RegSetValueEx is wrong: cbData must include the terminating NUL character, so this should properly be strlen(strtemp) + 1.
Other problems with your code include the fact that there is absolutely no error checking. If the attempt to create the registry key fails, then you should not attempt to write into it, nor should you attempt to close it.
Also, there is never a reason in the year 2017 to call the ANSI version of a Windows API function. Everything has been Unicode internally for almost two decades, and your code needs to get with the program. This means using strings consisting of wchar_t characters.
Related
I am trying to hook a user-defined function of a program written in Delphi using C++ and Detours library. (DLL Injection)
However, I can't hook it because Delphi's and C++'s function calling conventions don't match.
Delphi uses the fastcall function calling convention, and C++ also provides a fastcall function calling convention.
However, Delphi's fastcall stores its arguments sequentially on EAX, EDX, ECX, and the stack, whereas C++'s fastcall stores its arguments sequentially on ECX, EDX, and stack. (This is because there is no standard for fastcall.)
Due to these differences, I have no way to get the arguments stored in EAX.
How can I solve this problem?
(This article has been translated by Google Translate.)
< dllmain.cpp >
#include "pch.h"
typedef void(__fastcall* ORGFP)(char); //Prototype of function to hook (reverse engineering)
ORGFP originFunc1 = (ORGFP)((DWORD)GetModuleHandle(NULL) + 0x2B2F20); //Image base of target process + offset of function to hook
ORGFP originFunc2 = (ORGFP)((DWORD)GetModuleHandle(NULL) + 0x2B2A20);
DWORD WriteLog(LPCTSTR lpszFormat, ...) {
TCHAR szLog[512];
DWORD dwCharsWritten;
va_list args;
va_start(args, lpszFormat);
_vstprintf_s(szLog, 512, lpszFormat, args);
va_end(args);
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), szLog, _tcslen(szLog), &dwCharsWritten, NULL);
return dwCharsWritten;
}
void __fastcall DetourFunc1(char on) {
WriteLog(TEXT("Function called : BlockInternet(%d)\n"), on);
return originFunc1(on);
}
void __fastcall DetourFunc2(char on) {
WriteLog(TEXT("Function called : BlockInputDevices(%d)\n"), on);
return originFunc2(on);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (DetourIsHelperProcess())
return TRUE;
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
AllocConsole();
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)originFunc1, DetourFunc1);
DetourAttach(&(PVOID&)originFunc2, DetourFunc2);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
FreeConsole();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)originFunc1, DetourFunc1);
DetourDetach(&(PVOID&)originFunc2, DetourFunc2);
DetourTransactionCommit();
break;
}
return TRUE;
}
< pch.cpp >
#include "pch.h"
< pch.h >
#ifndef PCH_H
#define PCH_H
#include "framework.h"
#include <stdio.h>
#include <stdarg.h>
#include <tchar.h>
#include <detours.h>
#endif
< framework.h >
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
I solved this problem using __declspec(naked)! Thanks to everyone who helped me!
#include <iostream>
#include <Windows.h>
#include <detours.h>
using namespace std;
__declspec(naked) void __fastcall originFunction(char arg) {
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}
__asm {
mov byte ptr [arg], al
}
cout << (int)arg << endl;
__asm {
mov esp, ebp
pop ebp
ret
}
}
typedef void(__fastcall* FP)(char);
FP originFunctionPointer = originFunction;
__declspec(naked) void __fastcall detourFunction(char arg) {
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}
__asm {
mov byte ptr [arg], al
}
cout << (int)arg << endl;
arg = 0;
__asm {
mov al, byte ptr [arg]
call dword ptr [originFunctionPointer]
}
__asm {
mov esp, ebp
pop ebp
ret
}
}
int main() {
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)originFunctionPointer, detourFunction);
DetourTransactionCommit();
__asm {
mov al, 1h
call dword ptr [originFunction]
}
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)originFunctionPointer, detourFunction);
DetourTransactionCommit();
return 0;
}
As per wikipedia:
Borland register
Evaluating arguments from left to right, it passes three arguments via EAX, EDX, ECX. Remaining arguments are pushed onto the stack, also left to right.[12] It is the default calling convention of the 32-bit compiler of Delphi, where it is known as register. This calling convention is also used by Embarcadero's C++Builder, where it is called __fastcall.[13] In this compiler, Microsoft's fastcall can be used as __msfastcall.[14]
GCC and Clang can be made to use a similar calling convention by using __stdcall with the regparm function attribute or the -mregparm=3 switch. (The stack order is inverted.) It is also possible to produce a caller clean-up variant using cdecl or extend this to also use SSE registers.[15] A cdecl-based version is used by the Linux kernel on i386 since version 2.6.20 (released February 2007).
https://en.wikipedia.org/wiki/X86_calling_conventions#Borland_register
I am using mmsystem.h to read joystick data in windows. Following strucure is used for reading
typedef struct joyinfoex_tag {
DWORD dwSize;
DWORD dwFlags;
DWORD dwXpos;
DWORD dwYpos;
DWORD dwZpos;
DWORD dwRpos;
DWORD dwUpos;
DWORD dwVpos;
DWORD dwButtons;
DWORD dwButtonNumber;
DWORD dwPOV;
DWORD dwReserved1;
DWORD dwReserved2;
} JOYINFOEX
JOYINFOEX joyInfoEx;
joyGetPosEx(0, &joyInfoEx);
I want to send force feedback to the joystick. Can any one help me to do this ?
Based on the available documentation, there does not seem to be direct support for controller FeedBack via the mmsystem interface.
I'm writing optimized Windows based shellcode in C++ and I have problem avoiding hardcoded addresses in C++ while passing it to function.
e.g:
My_CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)&thread_callback, NULL, NULL, NULL);
DWORD WINAPI thread_callback(LPVOID lpParam)
{
// stuff..
}
in disassembly, it shows CreateThread(..., cardcoded_address, ..);
instead, I want to pass this address like "from this location to thread_callback"
is there any way to avoid it? (because shellcode should be address independent?)
Regards.
Anyways, I was searching/doing some stuff and the final thing I've could done is that you can solve this with delta offset.
Explanation: at the very first function of your code, there should be function like this:
DWORD delta;
__asm {
call GetBasePointer
GetBasePointer:
pop eax
sub eax, GetBasePointer
mov [delta], eax
}
You can also google for delta offset for more details.
Afterwards, you can do something like this:
My_CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)((DWORD)thread_callback + (DWORD)delta), NULL, NULL, NULL);
DWORD WINAPI thread_callback(LPVOID lpParam)
{
// stuff..
}
and it will work fine,
Regards.
So i am currently learning about hooking and injection and build a little test application for myself. What i am doing in there is:
Allocating some memory inside the process (using VirtualAllocEx)
Writing code to this code-cave (using WriteProcessMemory)
Hooking a function inside the app to jump to this code-cave
Now i have some problems which i am unsure of why they occur.
My code for creating the cave is this:
DWORD procID = GetCurrentProcessId();
HANDLE procHandle = OpenProcess((PROCESS_VM_WRITE | PROCESS_VM_OPERATION), false, procID);
if (procHandle == NULL) {
std::cout << "OpenProcess failed..." << std::endl;
return -1;
}
DWORD leng = (unsigned int)dynASM_end - (unsigned int)dynASM;
leng += 270;
LPVOID allocAddr = VirtualAllocEx(procHandle, NULL, leng, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
std::cout << "BaseAddr: " << allocAddr << std::endl;
int check = WriteProcessMemory(procHandle, (void*)((char*)allocAddr + 0x10E), dynASM, leng - 270, NULL);
unsigned int bExec = 1;
check = WriteProcessMemory(procHandle, allocAddr, &bExec, sizeof(unsigned int), NULL);
if (check) {
std::cout << "Successfully written asm to process!" << std::endl;
}
Now this is very basic. VirtualAllocEx always returns 0x00030000, is this possible?
This is my simple assembly code:
void testCall()
{
std::cout << "Hook worked!" << std::endl;
}
__declspec(naked) void dynASM()
{
__asm {
push ebp
mov ebp, esp
call testCall
mov esp, ebp
pop ebp
ret
}
}
__declspec(naked) void dynASM_end()
{
}
I believe i can call the function testCall this way, can't i? This is the code which i put into the codecave as you can see above.
Now i have a offset to a function inside another class in which i want to hook. This function only consists of:
__declspec(naked) void Core::HookFunc()
{
__asm {
mov edi, edi
push ebp
mov ebp, esp
mov esp, ebp
pop ebp
ret
}
}
And i try to hook like this:
DWORD hookFuncOffset = 0x14510;
DWORD jumpTo = (DWORD)((char*)allocAddr + 0x10E);
DWORD baseAddr = (DWORD)GetModuleHandle(NULL);
BYTE* finalAddr = (BYTE*)((DWORD)baseAddr + hookFuncOffset);
DWORD oldProtect, bkpProtect, relAdr;
VirtualProtect(finalAddr, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
relAdr = (DWORD)(jumpTo - (DWORD)finalAddr) - 5;
*finalAddr = 0xE9;
*((DWORD*)finalAddr + 0x1) = relAdr;
VirtualProtect(finalAddr, 5, oldProtect, &bkpProtect);
allocAddr is the address for the code-cave i have allocated above.
Now while debugging it i can see that relAddr is 0xFFFABBF9 which seems really high to me. But if i look into the disassembly view of Visual Studio the jmp created leads to 0xF9939B14 which leads to an Access Violation Exception. I would believe that even if the jmp would lead to the "correct" address it would also throw an Exception. What am i doing wrong?
Debugging with visual studio 2005 The following Error Displayed :
Unhandled exception at 0x00000000 in procexp.exe: 0xC0000005: Access
violation reading location 0x00000000.
And Thread Information:
2704 Win32 Thread 00000000 Normal 0
extern "C" VDLL2_API BOOL WINAPI MyTerminateProcess(HANDLE hProcess,UINT uExitCode)
{
SetLastError(5);
return FALSE;
}
FARPROC HookFunction(char *UserDll,FARPROC pfn,FARPROC HookFunc)
{
DWORD dwSizeofExportTable=0;
DWORD dwRelativeVirtualAddress=0;
HMODULE hm=GetModuleHandle(NULL);
FARPROC pfnOriginalAddressToReturn;
PIMAGE_DOS_HEADER pim=(PIMAGE_DOS_HEADER)hm;
PIMAGE_NT_HEADERS pimnt=(PIMAGE_NT_HEADERS)((DWORD)pim +
(DWORD)pim->e_lfanew);
PIMAGE_DATA_DIRECTORY
pimdata=(PIMAGE_DATA_DIRECTORY)&(pimnt->OptionalHeader.DataDirectory);
PIMAGE_OPTIONAL_HEADER pot=&(pimnt->OptionalHeader);
PIMAGE_DATA_DIRECTORY
pim2=(PIMAGE_DATA_DIRECTORY)((DWORD)pot+(DWORD)104);
dwSizeofExportTable=pim2->Size;
dwRelativeVirtualAddress=pim2->VirtualAddress;
char *ascstr;
PIMAGE_IMPORT_DESCRIPTOR
pimexp=(PIMAGE_IMPORT_DESCRIPTOR)(pim2->VirtualAddress + (DWORD)pim);
while(pimexp->Name)
{
ascstr=(char *)((DWORD)pim + (DWORD)pimexp->Name);
if(strcmpi(ascstr,UserDll) == 0)
{
break;
}
pimexp++;
}
PIMAGE_THUNK_DATA
pname=(PIMAGE_THUNK_DATA)((DWORD)pim+(DWORD)pimexp->FirstThunk);
LPDWORD lpdw=&(pname->u1.Function);
DWORD dwError=0;
DWORD OldProtect=0;
while(pname->u1.Function)
{
if((DWORD)pname->u1.Function == (DWORD)pfn)
{
lpdw=&(pname->u1.Function);
VirtualProtect((LPVOID)lpdw,sizeof(DWORD),PAGE_READWRITE,&OldProtect);
pname->u1.Function=(DWORD)HookFunc;
VirtualProtect((LPVOID)lpdw,sizeof(DWORD),PAGE_READONLY,&OldProtect);
return pfn;
}
pname++;
}
return (FARPROC)0;
}
FARPROC CallHook(void)
{
HMODULE hm=GetModuleHandle(TEXT("Kernel32.dll"));
FARPROC fp=GetProcAddress(hm,"TerminateProcess");
HMODULE hm2=GetModuleHandle(TEXT("vdll2.dll"));
FARPROC fpHook=GetProcAddress(hm2,"MyTerminateProcess");
dwAddOfTerminateProcess=HookFunction("Kernel32.dll",fp,fpHook);
if(dwAddOfTerminateProcess == 0)
{
MessageBox(NULL,TEXT("Unable TO Hook Function."),TEXT("Parth"),MB_OK);
}
else
{
MessageBox(NULL,TEXT("Success Hooked."),TEXT("Parth"),MB_OK);
}
return 0;
}
Thanks in advance for any help.
004118AC mov esi,esp
004118AE push 0
004118B0 mov eax,dword ptr [hProc]
004118B3 push eax
004118B4 call dword ptr[__imp__TerminateProcess#8(4181E4h)]
004118BA cmp esi,esp
esi returned zero. why ?
What is VDLL2_API defined as? It may be interfering with the calling convention (which is meant to be WINAPI for this function, as you write it later on the same line).
Stack problems on exit (ESI, ESP) usually indicate that you have your calling conventions mixed up. You appear to have used FARPROC consistently everywhere else, but since you know the exact prototype of the function, try typedef-ing that as the type to use instead:
typedef BOOL (WINAPI *TERMINATEPROCESS_PROC)(HANDLE, UINT);
Now use TERMINATEPROCESS_PROC everywhere instead of FARPROC.
Don't write this kind of code yourself. Use the Detours library from Microsoft Research.