Wie springe ich die Programmausführung an eine bestimmte Adresse in C?
Lesezeit: 4 Minuten
Sam
Ich möchte, dass das Programm zu einer bestimmten Adresse im Speicher springt und die Ausführung von dieser Adresse aus fortsetzt. Ich dachte darüber nach, es zu verwenden goto aber ich habe kein Etikett, sondern nur eine Adresse im Speicher.
Sie müssen sich keine Sorgen um die Rückkehr von der Sprungadresse machen.
Bearbeiten: Verwenden des GCC-Compilers
Vielleicht hilft Ihnen das stackoverflow.com/questions/61341/…
– 0x90
16. November 2011 um 20:16 Uhr
Dies ist stark plattformabhängig. Welches Betriebssystem/Compiler verwenden Sie?
– Rotoglu
16. November 2011 um 20:16 Uhr
Schreiben Sie eine Art Exploit?
– Kerrek SB
16. November 2011 um 20:17 Uhr
C oder C++? Und warum willst du das tun?
– David Heffernan
16. November 2011 um 20:32 Uhr
Verstehen Sie, dass, wenn Sie dies tun (entweder mit einer Inline-Assembly-Sprunganweisung oder einem Funktionszeiger-Bodge), alle Variablen ihre Werte über den Sprung hinweg nicht unbedingt behalten? Eine Variable kann an dem Punkt, von dem aus Sie springen, in einem Register und an dem Punkt, zu dem Sie springen, in einem anderen Register zwischengespeichert werden. Dies setzt voraus, dass sich die beiden Punkte sogar in derselben Funktion befinden. Wenn es sich bei der Zieladresse also um in C geschriebenen Code handelt, funktioniert dies fast garantiert nicht.
– Steve Jessop
17. November 2011 um 0:58
Randall Cook
Inline-Assembly ist möglicherweise die einfachste und „eleganteste“ Lösung, obwohl dies höchst ungewöhnlich ist, es sei denn, Sie schreiben einen Debugger oder ein spezielles introspektives System.
Eine andere Möglichkeit könnte darin bestehen, einen Zeiger auf eine void-Funktion zu deklarieren (void (*foo)(void)), dann setzen Sie den Zeiger so, dass er Ihre Adresse enthält, und rufen Sie ihn dann auf:
Es werden Dinge auf den Stapel verschoben, da der Compiler davon ausgeht, dass Sie einen Unterroutinenaufruf ausführen. Da Ihnen die Rückgabe jedoch egal ist, funktioniert dies möglicherweise.
Ich habe es mit meinem Setup getestet, mit gcc und mit Nucleus, habe einen minimalen Bootloader geschrieben und es funktioniert …..
– fazkan
5. Januar 2016 um 13:23
Einige Compiler werten möglicherweise die Speicheradresse (in diesem Fall 0x12345678) als aus intund beschweren Sie sich, wenn Sie versuchen, den Wert des Funktionszeigers darauf zu setzen. Sie sollten die Speicheradresse explizit umwandeln: void (*foo)(void) = (void (*)())0x12345678;.
– Tyrel Kostyk
13. Februar 2020 um 20:10 Uhr
gcc hat eine Erweiterung, die das Springen zu einer beliebigen Adresse ermöglicht:
void *ptr = (void *)0x1234567; // a random memory address
goto *ptr; // jump there -- probably crash
Das ist so ziemlich das Gleiche wie die Verwendung eines Funktionszeigers, den Sie auf einen festen Wert setzen, aber es wird tatsächlich eine Sprunganweisung anstelle einer Aufrufanweisung verwendet (sodass der Stapel nicht geändert wird).
Beachten Sie, dass dies wirklich GCC-spezifisch ist. Clang erlaubt dies nicht.
Ein aktuelles Update von Atmel Studio hat diese Linie durchbrochen, die seit einem Jahrzehnt funktioniert … asm("jmp " STR(FLASH_ACTIVE_IMAGE_START_ADDRESS) ); …aber durch die obige Syntax ersetzt funktioniert. Danke!
– bigjosh
9. Mai 2021 um 7:56 Uhr
#include <stdio.h>
#include <stdlib.h>
void go(unsigned int addr) {
(&addr)[-1] = addr;
}
int sub() {
static int i;
if(i++ < 10) printf("Hello %d\n", i);
else exit(0);
go((unsigned int)sub);
}
int main() {
sub();
}
Dies ruft natürlich undefiniertes Verhalten hervor, ist plattformabhängig und setzt voraus, dass Codeadressen die gleiche Größe haben wie intusw. usw.
Das ist genial. Ich wollte C als Sprach-Backend verwenden und wollte wissen, wie man zu beliebigen Adressen springt. Dann habe ich das gefunden.
– kirbyfan64sos
23. November 2014 um 20:48
Ich kann dafür garantieren, dass dieser Trick meistens funktioniert, solange die Zielfunktion keine Argumente hat und Sie nicht versuchen, einen Wert zurückzugeben. Ich habe es geändert void* anstatt unsigned int und das hat bei mir funktioniert. Aber als allgemeine Lösung zum Ersetzen von x86 JMP Inline ASM funktioniert es nicht gut genug.
– Chris Dolan
2. Juni 2015 um 14:09
Andro
Es sollte ungefähr so aussehen:
unsigned long address=0x80;
void (*func_ptr)(void) = (void (*)(void))address;
func_ptr();
Allerdings handelt es sich hierbei nicht um einen sehr sicheren Vorgang. Das Springen zu einer unbekannten Adresse führt wahrscheinlich zu einem Absturz!
U007D
Da die Frage ein C++-Tag hat, finden Sie hier ein Beispiel für a C++ Aufruf einer Funktion mit einer Signatur wie main()–int main(int argc, char* argv[]):
int main(int argc, char* argv[])
{
auto funcAddr = 0x12345678; //or use &main...
auto result = reinterpret_cast<int (*)(int, char**)>(funcAddr)(argc, argv);
}
Gemeinschaft
Haben Sie die Kontrolle über den Code an der Adresse, zu der Sie springen möchten? Ist das C oder C++?
Ich schlage es zögernd vor setjmp() / longjmp() wenn Sie C verwenden und ausführen können setjmp() wohin Sie zurückspringen müssen. Allerdings muss man damit SEHR vorsichtig sein.
Informationen zu C++ finden Sie in der folgenden Diskussion longjmp() Shortcut-Ausnahmebehandlung und Destruktoren-Destruktoren. Dies würde mich noch zögernder machen, die Verwendung in C++ vorzuschlagen.
C++: Sichere Verwendung von longjmp und setjmp?
İlkerK
Dies ist, was ich für meinen Bootstrap-Loader verwende (MSP430AFE253,Compiler = gcc,CodeCompeserStudio);
Vielleicht hilft Ihnen das stackoverflow.com/questions/61341/…
– 0x90
16. November 2011 um 20:16 Uhr
Dies ist stark plattformabhängig. Welches Betriebssystem/Compiler verwenden Sie?
– Rotoglu
16. November 2011 um 20:16 Uhr
Schreiben Sie eine Art Exploit?
– Kerrek SB
16. November 2011 um 20:17 Uhr
C oder C++? Und warum willst du das tun?
– David Heffernan
16. November 2011 um 20:32 Uhr
Verstehen Sie, dass, wenn Sie dies tun (entweder mit einer Inline-Assembly-Sprunganweisung oder einem Funktionszeiger-Bodge), alle Variablen ihre Werte über den Sprung hinweg nicht unbedingt behalten? Eine Variable kann an dem Punkt, von dem aus Sie springen, in einem Register und an dem Punkt, zu dem Sie springen, in einem anderen Register zwischengespeichert werden. Dies setzt voraus, dass sich die beiden Punkte sogar in derselben Funktion befinden. Wenn es sich bei der Zieladresse also um in C geschriebenen Code handelt, funktioniert dies fast garantiert nicht.
– Steve Jessop
17. November 2011 um 0:58