Ich denke, meine Frage mag ein wenig seltsam scheinen, aber hier geht es; Ich versuche, ein Programm dynamisch in C++ zu erstellen (hauptsächlich aus Spaß, aber auch aus programmatischen Gründen) und es ist nicht so schwer, wie es klingen mag. Um dies zu tun, müssen Sie Montag im laufenden Betrieb wie folgt verwenden:Ein gültiges Muster in Assembly für variadic Argumente
byte * buffer = new byte[5];
*buffer = '0xE9'; // Code for 'jmp'
*(uint*)(buffer + 1) = 'address destination'; // Address to jump to
Das ist viel einfacher, als es scheinen mag, weil ich nur eine Plattform und Compiler Ziel; GCC mit Linux 32bit (und auch nur eine Aufrufkonvention, cdecl). Ich versuche also, eine dynamische Assembly-Funktion zu erstellen, um Aufrufe von Triggern umzuleiten, so dass ich Klassenmethoden als Callbacks verwenden kann (sogar mit C-API-Bibliotheken (natürlich mit cdecl)). Ich brauche das nur um Zeiger und native Typen zu unterstützen (char, int, short etc ...).
Die obige Funktion ist diejenige, die ich in reiner Assembly erstellen möchte (im Speicher mit C++). Da die Funktion sehr einfach ist, ist ihr ASM auch einfach (abhängig von Argumenten).
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
Also in meinem Programm, ich habe einen ASM Mustergenerator erstellt (da ich weiß, ASM nicht besonders gut, ich nach Mustern zu suchen). Diese Funktion kann Assembler-Code (in Bytes, für den genauen obigen Fall, d. H. Eine Funktion, die umleitet und zurückgibt) durch Spezifizieren der Menge von Argumenten, die die Funktion benötigt, erzeugen. Dies ist ein Ausschnitt aus meinem C++ Code.
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
Wenn ich Null als stackSize
angeben dies wird der Ausgang sein:
55 push %ebp
89 e5 mov %esp,%ebp
e8 90 90 90 90 call <address>
5d pop %ebp
c3 ret
Wie Sie, das ist völlig gültig 32-Bit-ASM, und fungiert als ‚MyRedirect‘ sehen können, wenn es hatte null Argumente und keinen Bedarf für einen 'diesen' Zeiger. Das Problem ist, ich möchte den Teil implementieren, wo es ASM-Code generiert, abhängig von der Anzahl der Argumente, die ich angeben, dass die "Redirect" -Funktion erhalten wird. Ich habe das erfolgreich in meinem kleinen C++ - Programm von mir gemacht (knackte das Muster).
Diese Funktion gibt das exakt gleiche Muster aus wie der von 'objdump' generierte ASM-Code. Also meine Frage ist; wird dies in allen Fällen gültig sein, wenn ich nur eine Umleitungsfunktion wie die oben, egal die Argumente wollen, wenn es nur unter Linux 32bit, oder gibt es irgendwelche Fallstricke, über die ich wissen müssen? Beispielsweise; Wäre der generierte ASM anders als "shorts" oder "chars" oder funktioniert das (ich habe nur mit Ganzzahlen getestet), und auch wenn ich eine Funktion aufrufen würde, die "void" zurückgibt (wie würde das den ASM betreffen)?
ich ein bisschen unscharf alles erklärt haben könnte, so wenden Sie sich bitte an Stelle von Missverständnissen fragen :)
HINWEIS: Ich will nicht, Alternativen wissen, ich meine aktuelle Implementierung genießen und denke, es ist sehr interessant ist, ich Ich würde Ihre Hilfe zu diesem Thema sehr schätzen.
EDIT: Bei Interesse sind hier einige Deponien für die oben genannten C++ Code: link
Eine sehr gute Alternative zum manuellen Codieren von Anweisungen ist die [asmjit] (http://code.google.com/p/asmjit/) -Bibliothek (im Gegensatz zu dem Namen ist dies kein JIT-Compiler, nur etwas, das JIT-Compiler können verwenden). –
@afishwhoswimsaround Diese Bibliothek sah großartig aus. Buchstäblich. Das scheint genau zu sein, was ich brauche. Schnelle Frage; kann ich eine Funktion dynamisch mit dieser Bibliothek (mit malloc oder etwas) erstellen, so kann ich (mit Assembly 'jmp') andere Funktionen 'umleiten' ('haken') sie zu den generierten Funktionen? –
Ja, schau dir die Beispiele an http://code.google.com/p/asmjit/wiki/Examples –