Penso che la mia domanda potrebbe sembrare un po 'strana, ma qui va; Sto provando a creare un programma in modo dinamico in C++ (principalmente per il gusto di farlo, ma anche per una ragione programmatica) e non è così difficile come potrebbe sembrare. Per fare questo è necessario utilizzare assembly in fase di esecuzione in questo modo:Un modello valido in assembly per argomenti variadici
byte * buffer = new byte[5];
*buffer = '0xE9'; // Code for 'jmp'
*(uint*)(buffer + 1) = 'address destination'; // Address to jump to
Questo è molto più facile di quanto possa sembrare, perché a indirizzare una sola piattaforma e compilatore; GCC con Linux 32bit (e anche solo una convenzione di chiamata, cdecl). Quindi sto cercando di creare una funzione di assembly dinamico per reindirizzare le chiamate da trigger, quindi posso usare i metodi di classe come callback (anche con librerie API C (con cdecl ovviamente)). Ho solo bisogno di questo per supportare puntatori e tipi nativi (char, int, short ecc ...).
ANYTHING MyRedirect(ANY AMOUNT ARGUMENTS)
{
return MyClassFunc('this', ANY AMOUNT ARGUMENTS);
}
La funzione precedente è quella che voglio creare in assembly puro (in memoria con C++). Poiché la funzione è molto semplice, il suo ASM è semplice (dipende dagli argomenti).
55 push %ebp
89 e5 mov %esp,%ebp
83 ec 04 sub $0x4,%esp
8b 45 08 mov 0x8(%ebp),%eax
89 04 24 mov %eax,(%esp)
e8 00 00 00 00 call <address>
c9 leave
c3 ret
Quindi, nel mio programma, ho creato un generatore di pattern ASM (dato che non so ASM particolarmente bene, cerco modelli). Questa funzione può generare codice assembly (in byte, per il caso esatto sopra, cioè una funzione che reindirizza e restituisce) specificando la quantità di argomenti di cui la funzione ha bisogno. Questo è uno snippet dal mio codice C++.
std::vector<byte> detourFunc(10 + stackSize, 0x90); // Base is 10 bytes + argument size
// This becomes 'push %ebp; move %esp, %ebp'
detourFunc.push_back(0x55); // push %ebp
detourFunc.push_back(0x89); // mov
detourFunc.push_back(0xE5); // %esp, %ebp
// Check for arguments
if(stackSize != 0)
{
detourFunc.push_back(0x83); // sub
detourFunc.push_back(0xEC); // %esp
detourFunc.push_back(stackSize); // stack size required
// If there are arguments, we want to push them
// in the opposite direction (cdecl convention)
for(int i = (argumentCount - 1); i >= 0; i--)
{
// This is what I'm trying to implement
// ...
}
// Check if we need to add 'this'
if(m_callbackClassPtr)
{
}
}
// This is our call operator
detourFunc.push_back(0xE8); // call
// All nop, this will be replaced by an address
detourFunc.push_back(0x90); // nop
detourFunc.push_back(0x90); // nop
detourFunc.push_back(0x90); // nop
detourFunc.push_back(0x90); // nop
if(stackSize == 0)
{
// In case of no arguments, just 'pop'
detourFunc.push_back(0x5D); // pop %ebp
}
else
{
// Use 'leave' if we have arguments
detourFunc.push_back(0xC9); // leave
}
// Return function
detourFunc.push_back(0xC3); // ret
Se specifico zero come stackSize
questo sarà l'output:
55 push %ebp
89 e5 mov %esp,%ebp
e8 90 90 90 90 call <address>
5d pop %ebp
c3 ret
Come potete vedere, questo è del tutto valido a 32 bit ASM, e fungerà da 'MyRedirect' se aveva zero argomenti e nessuna necessità di un puntatore "this". Il problema è che voglio implementare la parte in cui genera il codice ASM, a seconda della quantità di argomenti che specifica che la funzione 'reindirizzamento' riceverà. L'ho fatto con successo nel mio piccolo programma in C++ (crackato il pattern).
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
int val = atoi(argv[1]);
printf("\tpush %%ebp\n");
printf("\tmov %%esp,%%ebp\n");
if(val == 0)
{
printf("\tcall <address>\n");
printf("\tpop %%ebp\n");
}
else
{
printf("\tsub $0x%x,%%esp\n", val * sizeof(int));
for(int i = val; i > 0; i--)
{
printf("\tmov 0x%x(%%ebp),%%eax\n", i * sizeof(int) + sizeof(int));
printf("\tmov %%eax,0x%x(%%esp)\n", i * sizeof(int) - sizeof(int));
}
printf("\tcall <address>\n");
printf("\tleave\n");
}
printf("\tret\n");
return 0;
}
Questa funzione stampa lo stesso modello del codice ASM generato da 'objdump'. Quindi la mia domanda è; sarà valido in tutti i casi se I solo desidera una funzione di reindirizzamento come quella precedente, indipendentemente dagli argomenti, se è solo sotto Linux 32bit, o ci sono delle insidie che devo conoscere? Per esempio; l'ASM generato sarebbe diverso con "cortometraggi" o "caratteri" o funzionerà (l'ho solo verificato con numeri interi), e anche se chiamo una funzione che restituisce 'void' (come influirebbe sull'ASM)?
avrei potuto spiegato tutto un po 'sfocata, quindi si prega di chiedere, invece di eventuali incomprensioni :)
NOTA: Non voglio sapere alternative, mi piace il mio attuale implementazione e penso che sia molto interessante, ho apprezzerei molto il tuo aiuto sull'argomento.
EDIT: In caso di interesse, qui ci sono alcune discariche per quanto sopra codice C++: link
Un'alternativa molto buona alle istruzioni di codifica a mano è la libreria [asmjit] (http://code.google.com/p/asmjit/) (contrariamente al nome, questo non è un compilatore JIT, solo qualcosa che I compilatori JIT possono usare). –
@afishwhoswimsaround Quella libreria sembrava fantastica. Letteralmente. Questo sembra essere esattamente ciò di cui ho bisogno. Domanda veloce; posso creare dinamicamente una funzione con questa libreria (con malloc o qualcosa del genere) così posso 'reindirizzare' (con assembly 'jmp') altre funzioni ('agganciarle') alle funzioni generate? –
Sì, guarda gli esempi http://code.google.com/p/asmjit/wiki/Examples –