Komentarz na YT autorstwa Kapa PL, zacytowany w całości (istotne z uwagi na przykładowy kod):
Nie rozumiem dlaczego tak nie może być :/ ET to nie jest adres danej linijki kodu ?
[bits 32]
push ET
call [ebx+3*4];printf
add esp,4
push 0
call [ebx];exit
ET:db 'Hello World',0xa,0
Odpowiedź:
Sprowadza się to do dość ciekawej rzeczy, którą jest ASLR (Address Space Layout Randomization), który jest używany w pewnej formie w asmloaderze. Konkretniej, ET jest adresem linijki kodu, który w momencie kompilacji jest znany assemblerowi, tj. który jest liczony od podanego (za pomocą dyrektywy [org TUADRES]) lub domyślnego (0) adresu początku kodu.
Natomiast, jeśli program będzie załadowany w losowe miejsce w pamięci (a nie w dokładnie to samo, które założył assembler w momencie kompilacji), to adresy bezwzględne (takie jak ET) będą niepoprawne.
Przykładowo, ET w Twoim przypadku jest pod adresem 0xF, co można odczytać np. disasemblując program (via IDA):
00000000 push 0Fh
00000005 call dword ptr [ebx+0Ch]
00000008 add esp, 4
0000000B push 0
0000000D call dword ptr [ebx]
0000000F aHelloWorld db 'Hello World',0Ah,0
Jak widać, push ET został przez assembler zmieniony na bezwzględną wersję, tj. push 0Fh (gdzie 0Fh to wspomniany adres ET ustalony w momencie kompilacji).
W momencie załadowania programu przez asmloader program jednak nie będzie załadowany pod adres 0, tylko pod adres wybrany przez system operacyjny w momencie realizowania żądania alokacji pamięci (który, w uproszczeniu, można traktować tożsamo z mechanizmem ASLR). Informacja o tym gdzie program jest ładowany pojawia się w drugiej linii outputu asmloader, np.:
gynvael:haven-windows> asmloader aaa
Simplified Assembly Loader v.0.0.2 by gynvael.coldwind//vx
Code loaded at 0x001c0100 (28 bytes)
W tym wypadku kod trafił pod adres 0x001c0100, a więc poprawnym adresem stringu "Hello World\n" będzie 0x1c010f a nie 0xf:
(hexdump pamięci)
001c0108 83 c4 04 6a 00 ff 13 48 65 6c 6c 6f 20 57 6f 72 6c 64 0a 00 cc ...j...Hello World...
...
(zrzut disassemblera)
001c0100 680f000000 push 0Fh
001c0105 ff530c call dword ptr [ebx+0Ch]
001c0108 83c404 add esp,4
001c010b 6a00 push 0
001c010d ff13 call dword ptr [ebx]
001c010f 48 dec eax (48, czyli litera 'H' z 'Hello World')
...
Co istotne, adres ten będzie za każdym uruchomieniem inny (tak działa ASLR).
By the way...
On 22nd Nov'24 we're running a webinar called "CVEs of SSH" – it's free, but requires sign up: https://hexarcana.ch/workshops/cves-of-ssh (Dan from HexArcana is the speaker).
Więc w tym wypadku, tj. w sytuacji w której stosowany jest ASLR (lub podobny mechanizm sprawiający, że nie znamy docelowego adresu gdzie kod znajdzie się w pamięci), nie możemy korzystać z bezwzględnych adresów.
Trik z call którego używam jest jednym z rozwiązań tego problemu. Można by go rozwiązać na jeszcze kilka innych sposobów, np. stosując relatywne adresowanie względem jakiegoś rejestru, w którym jest adres początku kodu (co jest trochę lepszym rozwiązaniem), np.:
[bits 32]
call addr
addr:
pop ebp ; w ebp jest adres addr
sub ebp, addr ; zakladajac org 0, przesuwam ebp
; na poczatek kodu programu
; od teraz mozna uzywac ebp+ETYKIETA do adresowania
; relatywnego
lea eax, [ebp+ET] ; tozsame z eax = ebp + ET
push eax
call [ebx+3*4];printf
add esp,4
push 0
call [ebx];exit
ET:db 'Hello World',0xa,0
Oczywiście gdybyśmy znali adres gdzie będzie załadowany nasz kod, to można by go podać w dyrektywie [org TUADRES] i nie bawić się w relatywne adresowanie, tylko korzystać z adresów bezwzględnych. W przypadku asmloadera niestety nie ma takiej opcji (choć z perspektywy czasu powinienem od tego zacząć w kursach).
I tyle :)
P.S. Od jakiegoś czasu bawię się pomysłem częstszego publikowania na blogu moich odpowiedzi z forów/mejli/komentarzy/etc - sporo pytań się powtarza, więc być może niektóre odpowiedzi by zainteresowały większe grono osób. Ma ktoś jakiś pomysł jak można by oznaczać takie posty? Myślałem o "FAQ:" albo "Q&A:", choć one nie do końca odpowiadają znaczeniowo tego typu postom.
Comments:
MOV przenosi dane z pod danej komórki w pamięci,
a LEA zapisuje adres tejże komórki pamięci,
która te dane przechowuje.
@( RGVLcmFpbg== ):
Ja urządzałem sobie google hacking i jest o 1go więcej,
w tym znalazłem jednego niezidentyfikowanego,
bo trafiłem na sam bez stronki, może to ten twój.
Brakowało mi 2óch bodajże, ale w internacie
nikczemniki z innych pokoi szybkim formatem
zabrali mi dostęp do wyników, a dysku
do tej pory nie chciało mi się odzyskiwać. :F
W sumie zaraz sam pozyskam twojego, bo podałeś URL.
EDIT: Znalazłem ten nagłówek.
Teraz wystarczy spreparować zapytanie.
Trochę mi to zajmie, bo użyję samego TCP.
Czyli LEA używa się np. jako "lea eax, [esp]", aby zapisać do rejestru EAX adres wartości wierzchołka stosu?
PS. Nie trudno się było domyślić, że klucz będzie pod "/img/asdf" :P
Połamałeś mi głowę swoim konkretnym przykładem.
Nie potrafię stwierdzić czy przykład da się nawet
zakodować w kodzie maszynowym. (EDIT: Da się.)
Co robi LEA:
http://stackoverflow.com/a/1658310/7715436
(Vol. 2A 3-525)[ http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf ]
W zasadzie można według kodowania tej istrukcji (LEA r32, m)
(http://gynvael.vexillium.org/dump/opcodes.txt)
uzyskać dowolną kombinację na jaką pozwala ModR/M + SIB,
czyli obrazując to mniej więcej na tyle (z wyjątkami):
https://en.wikipedia.org/wiki/X86#Addressing_modes
(dla twojego przykładu zachodzą szczególne zależności w jej kodowaniu)
@( RGVLcmFpbg== ): BTW jak uzyskałeś obrazek?
Wysłałem tam zapytanie GET ze zmienionymi
jednym lub/i obiema polami (?):
If-Modified-Since: /* znacznie starsza data */
If-None-Match: /* zupełnie inny hash */
i uzyskuję odpowiedź 200 OK, ale "Content-Length: 0" ;-;
@Gyn:
Tak mi DeKrain łeb połamał, że znalazłem w internecie,
że można w x86-64 adresować względem RIP/EIP.
[ http://wiki.osdev.org/X86-64_Instruction_Encoding#RIP.2FEIP-relative_addressing ].
"RIP-relative addressing allows object files to be location independent."
@everyone:
Tyle internetu to jeszcze nigdy nie przewijałem,
żeby znaleźć odpowiedzi i upewnić się. (od 23:30)
Po drodze z połowę chyba pogubiłem. :F
@( RGVLcmFpbg== ): BTW jak uzyskałeś obrazek?
Wysłałem tam zapytanie GET ze zmienionymi
jednym lub/i obiema polami (?):
If-Modified-Since: /* znacznie starsza data */
If-None-Match: /* zupełnie inny hash */
i uzyskuję odpowiedź 200 OK, ale "Content-Length: 0" ;-;
pastebin com j0VNxFzS
Samemu tego lepiej już nie zrobię,
a samo z siebie bardziej nie będzie działać.
"Niektóre kotki nie są z rodziny błędów WWW, są tu niejako w odwiedzinach ;>"
Dzielę się moją kolekcją znalezionych:
(pic 1/7) -- NOT FOUND --
(pic 2/7) R U A HACKER NINJA?
(pic 3/7) GOOD HACKER OR A HACKER?
(pic 4/7) DIZ BE HACKER?
(pic 5/7) -- NOT FOUND --
(pic 6/7) -- NOT FOUND --
(pic 7/7) OH NO! // pusty komentarz
(pic 8/7) HOW FAST CAN A HACKER RUN?
http://gynvael.coldwind.pl/6q1c61k.jpg
http://gynvael.coldwind.pl/xacrackme/cat.jpg
http://gynvael.coldwind.pl/img/getimagesize_gif.gif
http://gynvael.coldwind.pl/img/asdf (???)
Add a comment: