Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


C++ Hook without assembly?

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> General Gamehacking
View previous topic :: View next topic  
Author Message
LongBeardedLion
Expert Cheater
Reputation: 0

Joined: 10 Apr 2020
Posts: 174

PostPosted: Wed Jul 01, 2020 10:19 am    Post subject: C++ Hook without assembly? Reply with quote

I have been playing around with hooks using assembly. It helped me understand a little more assembly.

But now i need to hook functions using C++ code inside the hooked function. So basically instead of usin __asm . I will hook the function and throw my c++ code inside.

But i could not find videos about this on youtube. Most are with assembly.

Can anyone help me? Or give me an hint of what i should look for?
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8587
Location: 127.0.0.1

PostPosted: Wed Jul 01, 2020 7:39 pm    Post subject: This post has 1 review(s) Reply with quote

There are various libraries that can help with this (as well as manual means of doing it). Generally, this is referred to as 'detouring' a function. Some public libs that can help with it:

- Microsoft Detours: https://github.com/microsoft/detours
- MinHook: https://github.com/TsudaKageyu/minhook
- PolyHook: https://github.com/stevemk14ebr/PolyHook / https://github.com/stevemk14ebr/PolyHook_2_0
- subhook: https://github.com/Zeex/subhook

And loads of others. Essentially you are creating a jumping point that will jump to your DLL and continue execution as if your DLL was part of the code. The various above libraries have various degrees of features/support for the various types of functions and hooking methods.

The main thing generally in a setup like this is ensuring that the stack is being handled properly. Things like the functions calling convention, or the point at which you are hooking into the function will matter in how that is handled. It will also determine which library will work best for your needs.

With manual code caves, you can still use normal C++ code in naked functions, just that you are responsible for all means of stack handling and cleanup when jumping to and from your cave. You also have to account for the various other means of not messing things up such as the various status flags when doing conditional related things in your normal C++ code.

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
LongBeardedLion
Expert Cheater
Reputation: 0

Joined: 10 Apr 2020
Posts: 174

PostPosted: Thu Jul 02, 2020 7:33 am    Post subject: Reply with quote

Thank you atomOs,
Thats awesome Smile.

Just one question.
I have this impression that using _asm instead of a detour that uses C++, is faster and more code efficient. Or am i wrong, or is it irrelevant? Seems like _asm is going straight to the code, and its cleaner and faster?

But anyways. Its very confusing to use _asm only. And in C++ i can simply write a small program inside the injection.

Im trying to make an injection that logs all the registers that go through a certain function into a .txt in my desktop. Dont know if thats the best practice. Or if thats fast enough. But i was told that i can print to the console. However i have no idea where the console is in Age of Empires 2 or if i must create a console.
Back to top
View user's profile Send private message
Csimbi
I post too much
Reputation: 98

Joined: 14 Jul 2007
Posts: 3340

PostPosted: Thu Jul 02, 2020 3:19 pm    Post subject: Reply with quote

I think they meant the LUA console.
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8587
Location: 127.0.0.1

PostPosted: Fri Jul 03, 2020 2:10 pm    Post subject: Reply with quote

LongBeardedLion wrote:
Thank you atomOs,
Thats awesome Smile.

Just one question.
I have this impression that using _asm instead of a detour that uses C++, is faster and more code efficient. Or am i wrong, or is it irrelevant? Seems like _asm is going straight to the code, and its cleaner and faster?

But anyways. Its very confusing to use _asm only. And in C++ i can simply write a small program inside the injection.

Im trying to make an injection that logs all the registers that go through a certain function into a .txt in my desktop. Dont know if thats the best practice. Or if thats fast enough. But i was told that i can print to the console. However i have no idea where the console is in Age of Empires 2 or if i must create a console.


If you are not someone who has coded in ASM for years on end and are extremely efficient in optimizations and best practices, I would suggest avoiding naked code caves (using raw _asm blocks) whenever possible. The compiler will optimize your C++ code as needed and when possible that will more than likely generate better results, especially if your blocks of asm are large.

Doing simple small caves and such is fine, or if you know exactly what you are working to make, it's fine as well. But if you are doing things that are in-depth, it's usually not worth the hassle.

Console wise, you would need to make your own if you are injecting a DLL into the game and want to print information. You can use things like OutputDebugStringA/OutputDebugStringW which will write to the systems debug output. (You can use a tool like DbgView or DbgView++) Making your own and outputting to it is not hard though. Look into the 'AllocConsole' API to do that and how to set things up to make it work with "printf" and similar functions.

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
LongBeardedLion
Expert Cheater
Reputation: 0

Joined: 10 Apr 2020
Posts: 174

PostPosted: Fri Jul 03, 2020 8:53 pm    Post subject: Reply with quote

Ok so i have this dll injection that works except i cant make it run my C++ code in the middle of it.

So im hooking a function, writing back its stolen bytes. And then mov ECX to whiskas. Then i want to save the value in whiskas, that was in ECX. To a txt in the desktop. But its not even allowing me to compile because it says:

C2489 'whiskas': initialized auto or register variable not allowed at function scope in 'naked' function

And also:


Error C3068 'ourFunct': a 'naked' function cannot contain objects that would require unwinding if a C++ exception occurred




So this is my hook :


Code:

void __declspec(naked) ourFunct() {
   int whiskas = 0x0;
   __asm {
      mov esi, ecx
      mov cl, byte ptr[esp + 0x8]
      mov whiskas, ecx
   }
   //Beep(1000, 1000);

   
      std::ofstream file;
      file.open("C:/Users/j/Desktop/Test.txt");
      file << whiskas;
      file.close();

      __asm {
      jmp[jmpBackAddy]
   }

}


However if i remove all the txt file code, and just leave the Beep(1000,1000); that i commented out, then it compiles, and it injects and it works perfectly. But i wanted the code to work with writting for the txt


Sad

This is the full code:
Code:

#include <Windows.h>
#include <iostream>
#include <fstream>



bool Hook(void* toHook, void* ourFunct, int len) {
   if (len < 5) {
      return false;
   }

   DWORD curProtection;
   VirtualProtect(toHook, len, PAGE_EXECUTE_READWRITE, &curProtection);

   memset(toHook, 0x90, len);

   DWORD relativeAddress = ((DWORD)ourFunct - (DWORD)toHook) - 5;

   *(BYTE*)toHook = 0xE9;
   *(DWORD*)((DWORD)toHook + 1) = relativeAddress;

   DWORD temp;
   VirtualProtect(toHook, len, curProtection, &temp);

   return true;
}

DWORD jmpBackAddy;
void __declspec(naked) ourFunct() {

   int whiskas = 0x0;
   __asm {
      mov esi, ecx
      mov cl, byte ptr[esp + 0x8]
      mov whiskas, ecx
   }
   //Beep(1000, 1000);

   
           std::ofstream file;
      file.open("C:/Users/j/Desktop/Test.txt");
      file << whiskas;
      file.close()

      __asm {
      jmp[jmpBackAddy]
   }

}

DWORD WINAPI MainThread(LPVOID param) {
   int hookLength = 6;
   DWORD hookAddress = 0x4174A1;
   jmpBackAddy = hookAddress + hookLength;

   Hook((void*)hookAddress, ourFunct, hookLength);

   while (true) {
      Sleep(40);
      if (GetAsyncKeyState(VK_NUMPAD3)) {
         Sleep(40);
         Beep(500, 500); //just to know that my whiskas injection is in place
      }
   }

   FreeLibraryAndExitThread((HMODULE)param, 0);

   return 0;
}

BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) {
   switch (dwReason) {
   case DLL_PROCESS_ATTACH:
      CreateThread(0, 0, MainThread, hModule, 0, 0);
      break;
   }

   return TRUE;
}
Back to top
View user's profile Send private message
atom0s
Moderator
Reputation: 205

Joined: 25 Jan 2006
Posts: 8587
Location: 127.0.0.1

PostPosted: Sat Jul 04, 2020 3:19 pm    Post subject: Reply with quote

Naked functions are literally just that, they are blocks of code that have no automatic stack handling. There is no epilogue or prologue to deal with any local variables, stack cleanup, or calling convention handling. So it has no means of holding local variables or dealing with stack unwinds in the event of an exception.

To fix those errors, you can move 'whiskas' out of the function and make it a global. You can also take the file code and move it to a separate function, then call that function in your naked function.

_________________
- Retired.
Back to top
View user's profile Send private message Visit poster's website
LongBeardedLion
Expert Cheater
Reputation: 0

Joined: 10 Apr 2020
Posts: 174

PostPosted: Sat Jul 04, 2020 5:36 pm    Post subject: Reply with quote

Thank you atomos that solve the problem for now. It compiled.
I didnt expect it to work. Just wanted it to compile.
But then i injected it and its actually exporting my value in ECX to the txt in my desktop. How awesome. Wink

But it also bugged some things in the game even though it didnt crash and it was functional. Now i need to make sure that the function where im doing the injection, stays with the proper registers intact after the function that you told me to create ends. Right? Is that the right thing to do? Or i dont know what im talking about? How should i proceed? Because it seems like im just a monkey writting code blindly and hoping it works Shocked . Im not sure if this is actually ruining all the code inside the game.

From what i saw in the debugger, the detour assembly looks like a mess. And it goes around doing some weird stuff Shocked

This is what i did:
I put whiskas in the global as you said.
And made a void function outside of the naked function.
Then called it inside.

Here it is:

Code:
#include <Windows.h>
#include <iostream>
#include <fstream>

int whiskas;

void writeFileJ() {
   std::ofstream file;
   file.open("C:/Users/j/Desktop/Test.txt");
   file << whiskas;
   file.close();

}

bool Hook(void* toHook, void* ourFunct, int len) {
   if (len < 5) {
      return false;
   }

   DWORD curProtection;
   VirtualProtect(toHook, len, PAGE_EXECUTE_READWRITE, &curProtection);

   memset(toHook, 0x90, len);

   DWORD relativeAddress = ((DWORD)ourFunct - (DWORD)toHook) - 5;

   *(BYTE*)toHook = 0xE9;
   *(DWORD*)((DWORD)toHook + 1) = relativeAddress;

   DWORD temp;
   VirtualProtect(toHook, len, curProtection, &temp);

   return true;
}

DWORD jmpBackAddy;
void __declspec(naked) ourFunct(std::ofstream& file)
{
   

   __asm {
      mov esi, ecx
      mov cl, byte ptr[esp + 0x8]
      mov whiskas, ecx
   }

   writeFileJ();


   __asm {
      jmp[jmpBackAddy]
   }
}

DWORD WINAPI MainThread(LPVOID param) {
   int hookLength = 6;
   DWORD hookAddress = 0x4174A1;
   jmpBackAddy = hookAddress + hookLength;

   Hook((void*)hookAddress, ourFunct, hookLength);

   while (true) {
      Sleep(40);
      if (GetAsyncKeyState(VK_NUMPAD3)) {
         Sleep(40);
         Beep(500, 500); //just to know that my whiskas injection is in place
      }
   }

   FreeLibraryAndExitThread((HMODULE)param, 0);

   return 0;
}

BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) {
   switch (dwReason) {
   case DLL_PROCESS_ATTACH:
      CreateThread(0, 0, MainThread, hModule, 0, 0);
      break;
   }

   return TRUE;
}
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> General Gamehacking All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites