 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
Polynomial Grandmaster Cheater
Reputation: 5
Joined: 17 Feb 2008 Posts: 524 Location: Inside the Intel CET shadow stack
|
Posted: Mon Sep 27, 2010 1:10 pm Post subject: Injected message box |
|
|
I'm injecting some code into another process using VirtualAllocEx, WriteProcessMemory and CreateRemoteThread. I've tested this with some infinite loop code (a few nops and a jmp) which works perfectly, creating a thread that eats up 100% of my CPU time on one core.
What I'd like to do is call an API such as MessageBoxA from the remote process, but because of ASLR and the fact that the remote process may not be the same each time (I'm injecting into multiple versions of the same process) I'm having trouble detecting the address of such APIs so that they can be called from my injected code.
I'm guessing I'd need to identify the location of the IAT, then scan it for the address of the API that I want to call, somehow identifying it in the list. Any ideas how I'd go about this? _________________
It's not fun unless every exploit mitigation is enabled.
Please do not reply to my posts with LLM-generated slop; I consider it to be an insult to my time. |
|
| Back to top |
|
 |
tombana Master Cheater
Reputation: 2
Joined: 14 Jun 2007 Posts: 456 Location: The Netherlands
|
Posted: Mon Sep 27, 2010 1:34 pm Post subject: |
|
|
You could do it through the IAT of the remote process, or use CreateToolhelp32Snapshot to get a list of remote modules.
If you get the correct address of 'GetProcAddress' and put it in the code stub then you can get the other addresses with the code from there. |
|
| Back to top |
|
 |
atom0s Moderator
Reputation: 205
Joined: 25 Jan 2006 Posts: 8587 Location: 127.0.0.1
|
Posted: Mon Sep 27, 2010 3:10 pm Post subject: |
|
|
You can obtain the API (MessageBoxA) address inside your current application and inject a block to call the address. You can
Heres a small example I wrote for someone a while back:
| Code: | //
// Code Injection Example
//
// Coded by: atom0s
// Coded on: Oct. 08, 2009
//
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <tlhelp32.h>
/*
* The below byte array converts to a 'similar' look of the following
* C/C++ code. This has been converted to the asm bytes for injection.
*
void HelloWorld( void )
{
char* szMessage = "Hello World!";
char* szCaption = "Hello!";
HMODULE hModule = LoadLibraryA( "user32.dll" );
FARPROC fFuncProc = GetProcAddress( hModule, "MessageBoxA" );
( ( int ( WINAPI *)( HWND, LPCSTR, LPCSTR, UINT ) ) fFuncProc )( 0, szMessage, szCaption, 0 );
} */
BYTE btFunction[] = {
0x55,
0x8B, 0xEC,
0x83, 0xEC, 0x10,
0xC7, 0x45, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, // Replace String #1
0xC7, 0x45, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, // Replace String #2
0x68, 0xFF, 0xFF, 0xFF, 0xFF, // Replace String #3
0xE8, 0xFF, 0xFF, 0xFF, 0xFF, // LoadLibraryA
0x89, 0x45, 0xF4,
0x68, 0xFF, 0xFF, 0xFF, 0xFF, // Replace String #4
0x8B, 0x45, 0xF4,
0x50,
0xE8, 0xFF, 0xFF, 0xFF, 0xFF, // GetProcAddress
0x89, 0x45, 0xF8,
0x6A, 0x00,
0x8B, 0x4D, 0xFC,
0x51,
0x8B, 0x55, 0xF0,
0x52,
0x6A, 0x00,
0xFF, 0x55, 0xF8,
0x8B, 0xE5,
0x5D,
0xC3
};
bool InjectCode( DWORD dwProcId )
{
/*
* Our various needed strings for our messagebox
* function to properly work.
*/
char* szModule = "user32.dll";
char* szFunction = "MessageBoxA";
char* szMessage = "Hello world!";
char* szCaption = "Hello!";
/*
* Open our process with proper access so we can
* do various memory operations and such.
*/
HANDLE hHandle = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, 0, dwProcId );
if( hHandle == INVALID_HANDLE_VALUE )
return false;
/*
* Allocate memory for our strings and function,
* each string has it's own memory block.
*/
LPVOID lpString1 = VirtualAllocEx( hHandle, 0, 1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
LPVOID lpString2 = VirtualAllocEx( hHandle, 0, 1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
LPVOID lpString3 = VirtualAllocEx( hHandle, 0, 1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
LPVOID lpString4 = VirtualAllocEx( hHandle, 0, 1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
LPVOID lpFunction = VirtualAllocEx( hHandle, 0, 1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if( lpString1 == NULL || lpString2 == NULL || lpString3 == NULL || lpString4 == NULL || lpFunction == NULL ) {
CloseHandle( hHandle );
return false;
}
/*
* Write our strings to their memory.
*/
WriteProcessMemory( hHandle, lpString1, szMessage, strlen( szMessage ), 0 );
WriteProcessMemory( hHandle, lpString2, szCaption, strlen( szCaption ), 0 );
WriteProcessMemory( hHandle, lpString3, szModule, strlen( szModule ), 0 );
WriteProcessMemory( hHandle, lpString4, szFunction, strlen( szFunction ), 0 );
/*
* Fix our functions string addresses before writing
* it to the process memory. (Faster this way.)
*/
memcpy( (LPVOID)( (DWORD)&btFunction + 0x09 ), &lpString1, 4 );
memcpy( (LPVOID)( (DWORD)&btFunction + 0x10 ), &lpString2, 4 );
memcpy( (LPVOID)( (DWORD)&btFunction + 0x15 ), &lpString3, 4 );
memcpy( (LPVOID)( (DWORD)&btFunction + 0x22 ), &lpString4, 4 );
/*
* Fix the API calls inside our function as well.
*/
DWORD dwLoadLibrary = ( ( (DWORD)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "LoadLibraryA" ) - ( (DWORD)lpFunction + 0x1A ) ) - 4 );
DWORD dwGetProcAddr = ( ( (DWORD)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "GetProcAddress" ) - ( (DWORD)lpFunction + 0x2B ) ) - 4 );
memcpy( (LPVOID)( (DWORD)&btFunction + 0x1A ), &dwLoadLibrary, 4 );
memcpy( (LPVOID)( (DWORD)&btFunction + 0x2B ), &dwGetProcAddr, 4 );
/*
* Write our function to the last memory block.
*/
WriteProcessMemory( hHandle, lpFunction, &btFunction, sizeof( btFunction ), 0 );
/*
* Create a thread and call the function.
*/
HANDLE hThread = CreateRemoteThread( hHandle, 0, 0, (LPTHREAD_START_ROUTINE) lpFunction, 0, 0, 0 );
if( hThread == NULL ) {
CloseHandle( hHandle );
return false;
}
return true;
}
int __cdecl main( int argc, TCHAR* argv[] )
{
PROCESSENTRY32 pe32 = { sizeof( PROCESSENTRY32 ) };
HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hSnapshot == INVALID_HANDLE_VALUE )
return 0;
if( ! Process32First( hSnapshot, &pe32 ) ) {
CloseHandle( hSnapshot );
return 0;
}
do {
if( _tcsicmp( _T( "winmine.exe" ), pe32.szExeFile ) == 0 ) {
CloseHandle( hSnapshot );
InjectCode( pe32.th32ProcessID );
return 0;
}
} while( Process32Next( hSnapshot, &pe32 ) );
CloseHandle( hSnapshot );
return 0;
} |
_________________
- Retired. |
|
| Back to top |
|
 |
Polynomial Grandmaster Cheater
Reputation: 5
Joined: 17 Feb 2008 Posts: 524 Location: Inside the Intel CET shadow stack
|
Posted: Mon Sep 27, 2010 3:21 pm Post subject: |
|
|
I can get the base address of the module without using GetProcAddress, since I'm coding in .NET and the Process class provides a list of loaded modules. However, I don't know how to get the relative address from base to the exported function I want. Any ideas on how to do this? _________________
It's not fun unless every exploit mitigation is enabled.
Please do not reply to my posts with LLM-generated slop; I consider it to be an insult to my time. |
|
| Back to top |
|
 |
atom0s Moderator
Reputation: 205
Joined: 25 Jan 2006 Posts: 8587 Location: 127.0.0.1
|
Posted: Mon Sep 27, 2010 3:29 pm Post subject: |
|
|
Calculate it based on where your allocation is and where you are writing it inside your 'cave'.
Your VirtualAllocEx call will return the base of your cave.
API Address - Cave Base + Offset in cave - 4 _________________
- Retired. |
|
| Back to top |
|
 |
Polynomial Grandmaster Cheater
Reputation: 5
Joined: 17 Feb 2008 Posts: 524 Location: Inside the Intel CET shadow stack
|
Posted: Mon Sep 27, 2010 3:34 pm Post subject: |
|
|
I know how to calculate that offset, but it's the API address I need to find. I know the base address of the module, but not the actual address of the API. I can find the address of the ASCII names in the DLL image, but I don't know how they map to the address. _________________
It's not fun unless every exploit mitigation is enabled.
Please do not reply to my posts with LLM-generated slop; I consider it to be an insult to my time. |
|
| Back to top |
|
 |
tombana Master Cheater
Reputation: 2
Joined: 14 Jun 2007 Posts: 456 Location: The Netherlands
|
Posted: Mon Sep 27, 2010 3:52 pm Post subject: |
|
|
| Burningmace wrote: | | I know how to calculate that offset, but it's the API address I need to find. I know the base address of the module, but not the actual address of the API. I can find the address of the ASCII names in the DLL image, but I don't know how they map to the address. |
If you have the address of the API in your own process (Using GetProcAddress), and the module base address of the module in your own process, then calculate the difference between the remote module base and the 'local' module base, and add that difference to the API address in your own process. |
|
| Back to top |
|
 |
Polynomial Grandmaster Cheater
Reputation: 5
Joined: 17 Feb 2008 Posts: 524 Location: Inside the Intel CET shadow stack
|
|
| Back to top |
|
 |
atom0s Moderator
Reputation: 205
Joined: 25 Jan 2006 Posts: 8587 Location: 127.0.0.1
|
|
| Back to top |
|
 |
justa_dude Grandmaster Cheater
Reputation: 23
Joined: 29 Jun 2010 Posts: 893
|
Posted: Mon Sep 27, 2010 6:07 pm Post subject: |
|
|
The above suggestions work, but they're all kind of a pain to implement. Writing a native DLL for injection is just so much easier.
Otherwise, I'd probably look to inject a script engine (lua, underc, perl, python, ruby, whatever) if the target app is running on a system that either already has the script engine/libraries installed or can be made to install them. Then you can wrap the processes of creating remote memory for a script, writing the script to remote memory, asking the interpreter to execute the script and freeing the memory in a trivially simple function. All of the scripting languages I can think of include dynaloading and win32 api support.
Lastly, there are a few just-in-time compilers. If you go down the path you're heading, I /highly/ recommend looking into them. The process of writing and patching shell-code (i.e., the replace-strings in Wicca's btFunction) is ugly, error-prone, and very difficult code to maintain.
Cheers,
adude |
|
| Back to top |
|
 |
Polynomial Grandmaster Cheater
Reputation: 5
Joined: 17 Feb 2008 Posts: 524 Location: Inside the Intel CET shadow stack
|
|
| Back to top |
|
 |
justa_dude Grandmaster Cheater
Reputation: 23
Joined: 29 Jun 2010 Posts: 893
|
Posted: Tue Sep 28, 2010 12:09 am Post subject: |
|
|
| Burningmace wrote: | | Wiccaan wrote: | | Just import GetProcAddress and GetModuleHandle and invoke them |
Hadn't thought of the GetModuleHandle approach, I'll give it a go. I'm so glad ASLR doesn't switch the module load offset per-process :shock: |
AFAIK, it /does/ (with the exception of kernel32). I think that it was implied that you'd load the dll into your own process, call getmodulehandle to get the base address of the dll, call getprocaddress to get the offset of the function you wanna' map out in the target process, and apply the difference of the two to the base address of the same module's base address inside the target process (which you find w/ the tlhelp calls). It's arguably easier to just inject code to call getprocaddress directly from within the target process. |
|
| Back to top |
|
 |
angelababy Newbie cheater
Reputation: -1
Joined: 01 Aug 2010 Posts: 22
|
Posted: Tue Sep 28, 2010 2:18 am Post subject: |
|
|
Then you can wrap the processes of creating remote memory for a script, writing the script to remote memory, asking the interpreter to execute the script and freeing the memory in a trivially simple function. _________________
Welcome to my paintings website - |
|
| Back to top |
|
 |
Polynomial Grandmaster Cheater
Reputation: 5
Joined: 17 Feb 2008 Posts: 524 Location: Inside the Intel CET shadow stack
|
|
| Back to top |
|
 |
justa_dude Grandmaster Cheater
Reputation: 23
Joined: 29 Jun 2010 Posts: 893
|
Posted: Tue Sep 28, 2010 8:25 am Post subject: |
|
|
| It may not be a function of ASLR, but it is a fact that dlls are not always mapped into the same virtual address space from one process to the next. It is also a fact that getmodulehandle is only intended to retrieve information related to the calling process. |
|
| Back to top |
|
 |
|
|
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
|
|