Jump to content

Search the Community

Showing results for tags 'assembly'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Informatii generale
    • Anunturi importante
    • Bine ai venit
    • Proiecte RST
  • Sectiunea tehnica
    • Exploituri
    • Challenges (CTF)
    • Bug Bounty
    • Programare
    • Securitate web
    • Reverse engineering & exploit development
    • Mobile security
    • Sisteme de operare si discutii hardware
    • Electronica
    • Wireless Pentesting
    • Black SEO & monetizare
  • Tutoriale
    • Tutoriale in romana
    • Tutoriale in engleza
    • Tutoriale video
  • Programe
    • Programe hacking
    • Programe securitate
    • Programe utile
    • Free stuff
  • Discutii generale
    • RST Market
    • Off-topic
    • Discutii incepatori
    • Stiri securitate
    • Linkuri
    • Cosul de gunoi
  • Club Test's Topics
  • Clubul saraciei absolute's Topics
  • Chernobyl Hackers's Topics
  • Programming & Fun's Jokes / Funny pictures (programming related!)
  • Programming & Fun's Programming
  • Programming & Fun's Programming challenges
  • Bani pă net's Topics
  • Cumparaturi online's Topics
  • Web Development's Forum
  • 3D Print's Topics

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Website URL


Yahoo


Jabber


Skype


Location


Interests


Occupation


Interests


Biography


Location

Found 6 results

  1. Another day of college, another day of hell—I mean, a beautiful day to write a blog! Now, I may not know much about the ’90s, but for sure, nowadays people use mechanisms to defend their software against reverse engineering. However, that doesn’t mean they’re safe. Don’t take me wrong, but if you have a house made out of sticks, it will break easily. Therefore, there are higher and more complex mechanisms to defend themselves from the same branch. Yeah, I’m talking about anti-debugging, even though real-time debugging is so helpful. Signed by Cringe Blogger (i mean me ) Would you liek to tkae a look here? (#full blog post) Blog What is Anti-Debugging? So let’s stop the chitchat and get to the main point: what is this thing called anti-debugging? The name speaks for itself — anti + debugging, meaning “no debugging.” To achieve this, we use various anti-debugging techniques. This term refers to methods a program can use to detect if it is running under the control of a debugger (e.g., attach + exe [x32dbg]). What is Debugging? Stop asking too many questions! Debugging software lets you run the program step by step, checking each instruction as it goes. This helps you see how the program uses the stack, heap, and registers, and how memory and settings change during runtime. You can follow function calls, track data flow, and find potential weaknesses or hidden features in the program. In short, debugging gives you a peek into the program's inner workings, helping you understand its logic, find flaws, or reverse-engineer its functionality. In the end, anti-debugging is meant to ensure that a program isn’t running under a debugger. But still, it's better to have a house made of stones than one made of sticks. It holds the damage better. Debug flags Let's not rush directly to the implementation or bypass, let's talk about debug flags too (I mean, it's a part of anti-debugging, right?). Now of course we dont have a flag here but something like an indicator used to detect the presence of a debugger. It's a special type of flag that is used to signal whether a program is being "analyzed" by a debugger. #debuger-present .(How? Usually by checking specific memory location, registers, or certain conditions in the system.) Most of the time that flag / indicator or binary indicator is set to 0 or 1. These flags can be set in the process environment block (PEB) or in the thread environment block (TEB). If you're wondering: the PEB is a structure that contains information about the process, such as the process ID, the base address of the process, and the path of the executable. The TEB is a structure that contains information about the thread, such as the thread ID, the stack base, and the stack limit. `NtGLobalFlag` : The NtGlobalFlag is a system-wide flag stored in the PEB (Process Environment Block) structure. It is used to indicate whether a process is being debugged or not. The value of it is 0 by default, but it can be changed to some degree under process control. Environment and System-Level Checks Before we dive into the code, let's talk about some environment and system-level checks that can be used to detect a debugger. Debugger-Specific Environment Variables Some debuggers set environment variables to indicate that a debugger is attached. The program can query the system for the presence of these variables to determine if a debugger is attached. Checking for Debugger Processes Another way to detect a debugger is by checking for the presence of debugger processes. This can be done by enumerating the running processes and checking for the presence of known debuggers, such as OllyDbg, x64dbg, or IDA Pro. Enumerate processes using `CreateToolhelp32Snapshot` and check for known debugger process names. Detecting Debugger-Specific System Calls Some debuggers use specific system calls or insert their own hooks. By checking or analyzing the behavior of these system calls, we can detect the presence of a debugger. Functions that may help: NtQueryInformationProcess System Calls: NtCreateThread NtReadVirtualMemory NtWriteVirtualMemory Detection Techniques: IsDebuggerPresent One of the easiest ways to detect a debugger is by using the `IsDebuggerPresent` function. This function checks whether the calling process is being debugged by a user-mode debugger. If the function returns a non-zero value, the process is being debugged. Otherwise, the process is not being debugged. if (IsDebuggerPresent()) return -1; At a lower level, specifically in assembly language, the code would appear as follows: call IsDebuggerPresent test eax, eax jne debugger_detected debugger_detected: mov eax, -1 ret What’s happening here? The code is calling `kernel32!IsDebuggerPresent`, which generally checks the `BeingDebugged` flag in the PEB (Process Environment Block). If the flag is set, it jumps to the `debugger_detected` label, sets `eax` to `-1`, and returns. Otherwise, it continues execution." CheckRemoteDebuggerPresent Another way to detect a debugger is by using `CheckRemoteDebuggerPresent()`, which checks whether a process is being debugged by a remote debugger. This function takes a process handle as input and returns a non-zero value if the process is being debugged. Otherwise, it returns zero. BOOL ProcessIsBeingDebugged; if(CheckRemoteDebuggerPresent(GetCurrentProcess(), &ProcessIsBeingDebugged)) { if(ProcessIsBeingDebugged) { return -1; } } At a lower level, the code would look like this: lea eax, [ProcessIsBeingDebugged] push eax push -1; ;GetCurrentProcess() ;or mov edi, esp call CheckRemoteDebuggerPresent cmp [ProcessIsBeingDebugged], 1 jz debugger_detected debugger_detected: push -1 call ExitProcess What about x86-64?? lea rdx, [ProcessIsBeingDebugged] mov rcx, -1 call CheckRemoteDebuggerPresent cmp [ProcessIsBeingDebugged], 1 jz debugger_detected debugger_detected: mov eax, -1 call ExitProcess What can we observe here? The code is invoking `kernel32!CheckRemoteDebuggerPresent`, a function that determines if the process is being debugged by a remote debugger. This function is also part of Windows API (the same as `IsDebuggerPresent`). If the process is being debugged, it triggers the `debugger_detected` label, sets `eax` to `-1`, and exits the process. Most of the time the logic behind these functions is the same, but the implementation may differ by that i mean the logic of the code. PEB!BeingDebugged Flag We talked about IsDebuggerPresent and CheckRemoteDebuggerPresent, but what about the PEB (Process Environment Block)? The PEB is a structure that contains information about the process, such as the process ID, the base address of the process, and the path of the executable. The PEB also contains a flag called `BeingDebugged` that indicates whether the process is being debugged. If the flag is set, the process is being debugged. Otherwise, the process is not being debugged. By using this method we dont need to call any function. We can directly check the flag in the PEB. #ifdef _WIN64 PEB pPEB = (PPEB)__readgsqword(0x30); #else PPEB pPEB = (PPEB)__readfsdword(0x60); #endif if (pPEB->BeingDebugged) { return -1; } 32-bit: mov eax, fs:[30h] cmp bye ptr [eax+2], 0 jne debugger_detected 64-bit: mov rax, gs:[60h] cmp byte ptr [rax+2], 0 jne debugger_detected In both cases, the PEB address is fetched from the FS or GSsegment, depending on the architecture: For 32-bit, the PEB address is stored at offset `0x30` in the FS segment. For 64-bit, the PEB address is stored at offset `0x60` in the GS segment. FS is used to store the base address of the Process Environment Block (PEB) in 32-bit Windows. GS is used to store the base address of the PEB in 64-bit Windows. The BeingDebugged flag is located at offset `0x2` in the PEB. If this flag is set (non-zero), it indicates that the process is being debugged. If the flag is not set (zero), the process is not being debugged. Bypassing Anti-Debugging Techniques We took a look at some of the most common anti-debugging techniques, but how can we bypass them? Let's take IsDebuggerPresent as an example. call IsDebuggerPresent test eax, eax jne debugger_detected ... [code] We will analyse the code again and see how can we "bypass" it. The code calls `IsDebuggerPresent` to check if the process is being debugged. It tests the return value of `IsDebuggerPresent` by performing a bitwise AND operation with itself. 3. If the result is non-zero, it jumps to the `debugger_detected` Now , IsDebuggerPresent is one of the easiest anti-debugging techniques to bypass. Why? because we can patch the jump instruction to skip the `debugger_detected` label. call IsDebuggerPresent test eax, eax nop ... [code] Final Thoughts You might be wondering, "What about the other functions?" It's important to recognize that not all anti-debugging mechanisms are implemented in the same way. For instance, while an if statement can often be bypassed by patching the jump instruction, a while statement presents a different challenge. This is why I'm preparing a new blog post focused on bypassing various anti-debugging techniques (though not all of them). The examples I'll be discussing will be drawn from PicoCTF and Crackmes. P.S: I'm not going to post only about bypassing anti-debugging techniques, but also about how to implement them. I’m also looking forward to meeting people with experience in Reverse Engineering. I see myself as an amateur that whishes to learn more and more, day by day.
  2. (Salut ..?) Invat de ceva timp ASM-ul , nu am avut timp de o carte , le bajbii momentan pe ici colo, si am zis sa trec la ceva mai interesant. Am selectat ca tot plodu' primul joc clasic jucat (o strategie de prin 2002) si zic hai sa fac ceva frumos sa intru in rand cu lumea . Mi-am atins intocmai scopul propus , nefiind de altfel vreo filosofie si m-am gandit sa imi scriu si un programel care sa imi automatizeze treaba odata rulat. Vreau sa editez valoarea unei adrese (cunoscute) in memorie a unui proces X insa cat mai direct fara multe bazaconii . Din ce m-am interesat pana acum, am cateva optiuni prin c++, dll inject .. dar nu am gasit o solutie sau un raspuns concret in legatura cu posibilitatea de a face totul din ASM fara a implica limbaje high-level . Sunt constient ca sunt obligat sa folosesc totusi o functie externa dar e si asta ok decat sa ma apuc de dll-uri tinand cont ca mi-am propus un anumit target de experienta pana la altele. Sunt o persoana practica, mai rar aplic concepte si teorii, apreciez insa orice fel de ajutor oferit. Compilator : NASM . Multumesc.
  3. Obiectivul este sa faceti in asa fel incat sa nu explodeze bomba Asta e putin mai lunga, codul l-am scris in Ansi C folosind si cateva linii de Inline Assembly AT&T Syntax -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 begin 755 atomic.gz M'XL("`L0]T\``V%T;VUI8P"=6'ML%,<9GUV?'Q"@9P/%$(H.U01CP?&H`;LJ M+7[QBL$.&$)X+>>[M>_@[O9TMQ>."*G`Q:E<QRIJ*E,IJ`455:VJJHFJM*C0 MRLE%1$BI1%/^0!6JJ`K2(=R*2`FJU)3K[YN9W9M;C%1UI6]G?O/]YON^><_N MMWMZMVB:QIQ'9U6,T,6\KZZ5TCI1WLH"K)8ULR7L>5;#,>0T.)"[R)-40WR0 M*L@\&)EWQE=',A=XKM1I4OB#NB11&"2A^LPO]+QL`CJ('P6-D!JIUY&<`C@% M'<E-8)(:Z8.D&?QF^";I!NY6="_=MR-LFL>IOSH>&UP=CZR*QY+97#!C!=>) M<K^,?>NNO;*O1)T&66^>;#OIN\,/9[SWPO6)G?,_W?N+]*/`QKJ?]Y.N5G*K M)=?K7Y-V5?N:Y&,(`@[OER_^?=(;OZ;D`[+-SD,Q;O+@%1[<YL&+(+/>\-51 MO/74>L,83EA)(V.'TK9A,'13F+IG`S.V]Z$T$DL:V8P9`2^6L<+M[48F'$H. ML536SK!4.I:TAZ"B6M)$(A1+LJV]VSN[C'7!C6YNC6P]S44=K=+P]LO^IV=! M+#:;>F^?+/-SK+.C4M][WE=7@\XXA+06Z5%*T9D12M'I44K1J#BEZ-B]H_?W MY*=\1:I[\$QA,\9Q[*TO2J72R"=V=7$)2HO5,%,\!QO[#]XHE-8/H&9IV7Z\ MJ4YI&7F*4O;!750K+2./4=(]N,DQ>8Y2J`\F.:8(HHV$W^&8(HG2D#VX"*B. MZ=I_'!G]6_[>H_Z!W='^$;".XO72OF@+DN);(']VKN*1;3F]*4?!9;]UZ132 MJS96R9F'*;S?_[>>?ZBUW\XL&?\-V<]/:C\A2FG>"*DYO?UVNGB]F@QH^0]] M!P\7QNT7V/BUY<2'_?Q4XZ4<N".3=L,5*D-FQD>^)BHKW;Q1."<X*/%C\A27 M(,@K--5O%%S%0E)4D\)7J5A.BJDG4+!*!3?U9U)4<\7HW4W43]G#?SQ=R?E5 MF5.IF"!%;5G1=J4#Q:.^IN(ATNP%&-][>W2@R4=E^U%VHW"%EM15"D6XN?<H M/^4O_AZ!P^I^LKJY'*O3_][^>GG?GF(?LF<*]^O1X5.+BV/_*97&KS;"S'B> MWBL^>K^DCY3LIK6/QWK\H]U-=6,]LY#XQGHHP-(/?DVL_'6M_4GZK_D/%Q\\ M8APNC"UN*KCC?8GVR?R_2O;<JY0;.I=_Z"O='*M"4?8S,8@NUYGG^Q%-\6.$ M\@KF=!7?/W36TM+2:5F)I6R790<BL4PHG3`C2UFGE1@LPT#8BIB!=5]K;]L@ M-!U4/#-D6XE8^)L!MBS#[?3U[432PN=Q2<[KDC*_-;E^9T%\.&^PB-G4B-AO MXMBW/W]2LBX@I=%<>19K&NDUX)E(CT&>D_7G2WO4AG[,6MHWFYG8C^MIOX#< M07W*WT)*>QLMSKDRQ1!:EU&.T"R*Z1'2B;.^.O9_/'0>.?D=:-,!R#'(:Y#O MYLNZK5U=7P\T=YN#L5`RT!IL#:Y?U;9"9*;3K5WC*%DP<S)AAP:1VFF11IT< M=E@SG6+!I&6;P8[.[:OLT+!$P\EL<#`;PZD6BS".HJ%,E`4C)Y.P)U([+32O MFNE,S$I6``.ZM!DGGLBDXC8YC.%MFSF\AP"@LB(A.\2"9M082H<2)@N&;2N= M@0.1'`NGN;,09@H<6#9_"6NBYF`&M+"52)A)^W_O]^=9^>SD]PY-C*_S.&?C M5YDX@_D<H?N!)LY*Y_')=*W"VP;>-O":IN%M8^)L)A[-V3AX='[5*#P2.HL? M8UX1C^;T!>G7R]O%Q+PF'LWU:^"E9"P:*]]#Z.RKDCQ:&RMUL2:\[3W"^)KC M?FE.3R`S1_&K2SG.Q#J@/*V%R[IHA^J7GM<@,V0=6DNW=+&&U'80SBL\6GMW M=+$FB3=;X;TI[?.[%]:'KTKX]?;S=Q1>*]U-P3OJX9%\7^'1'?8B>+UZF>?< M(7ZH\&C/F<(@+I[&[X]8>5[58<.G3>C0-+R?*KP(>)&:LD[EO2-Y-';\?ELC M^L'+^ZW"HX,Y]0S>'Q0>'<"Y9_@MR+82C]^;:\2=N5;AD?V/%7MTC^JM?=H> MR9\4'NVY_;5/KR.2OZCM`"]5.WT[[DK_O!W@Y9[!NR_M.7.$>.T*S_F^J&>5 M]^MWP?NGA^>DRO1@_9B<DW#V%>17L_)ZF^&QY\<A<D"IJ-Z]O0_M1XS7%ZQF M%PL#VUPL/,1=+%I]P<7\*X#O"P*+5;?RK(/%:$ZX6/3@91?/X/B6BV=R?,?% MSW'LRSMX%L>M+I[-\447S^&8UH_`7^*8UHG`8K5%7%S/<73"P0T<IUPL=NR< MB^=Q?,K%XJ3O/>_@+W/<[^(%PIZ+&X4]%R]DZE.%+QQUW'SLT](L)3X-\2U2 MXM,07[,2GX;X<""SF[(_=/3'B]*?F(<+V0&*_[RXTQ"FKX0UKY?Y7O]TY,45 M_V>4_M/0?]_S^'\;Z>1(V=Z['GMT-[WRNG/OF,/WBR4C9?R!TG^:OH#=5MK/ M]`;VP(._4,9#T^<S^C!R^CN`_J9O=?I.H9G:`/L!K3Q?""\'_C'B62CQ*J4# M`I!O>'"_)N:3\PWZ,O"`4O^@5IY_#9A_(>`[BCZFV*/9]@;PY]"OD/HWM<IO MW+>5]OC1GI\!VQ+7ZXWL/<(3#I[+/J#O2_@_(.U]XO%W3RO//S_&XQ%P08GO ML8?OQY9P6N'/!TXH_$5Z);\%^`U%OU:O]-<&_#NG?_0YK`^8OAV72OZ`7E[O M#;3>PVD[8V>'AH)A?*MW#?3M-GJW[QG`U[YA=%>@'5T*B%C&<-P:#,4-?L\S M0MD<PQTN%3=M,Q)<W]ZVCI'"B$5RA%H9OQP:D6PB<=+QT[.KF]O:LKMC9X^+ MR(V3+WL)NUXB9L)"K"=B:3/#[#2L;>WMZ^SH-?JV;-G3,V`,='3V]E!ENJL: MH70Z=-(PDY'*`OX[@AG=K^SJV+F]B]%%U"D3_RO"F:S!+[BR>#AMFDGO_Q!C MQZO&;G,XEL$MO"L>RF00D3&4,J(G6)K^BG`#9BX5Q]?3TS]"-F\N___@GUE/ M_U6IB"N2L8QH*!F)F\[0.-WD1LROY^+'BVK=,'#'EG8&XZ'P<<\/FS)W(^-] M-1C/FOPOCFKEI!F/6R=`X-=V6-C0MB$X;-I&*FS8T6SR>'`PQ_@?'A''?P&3 '&T4?:A0````` ` end -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) iF4EAREIAAYFAk/3EEIACgkQiOFy19RY1SC2gQD/XaoNjS8SRkLVcOGUiUzAOmRc wNBqEzVl896RaPmexGoBAJyJpYCmcG4qlVJUzOw4/87Q13QKxNgi+H4u/kUQhAt1 =J10j -----END PGP SIGNATURE----- Faceti in asa fel incat bomba sa nu explodeze, [pyth0n3@mc]$ ./atomic Bomb Armed atomic> test ***BOOM**** Atentie: Nu modificati datele ci doar fluxul. Download the key, check signature, decode and open archive wget -q -O - http://sprunge.us/dgLH | gpg --import wget http://sprunge.us/XWQT -O atomic.asc && gpg --verify atomic.asc uudecode atomic.asc && gunzip atomic.gz Probabil nu va rula in 64 biti deoarece m-am folosit de registrii Intel 32 biti in cateva linii de Inline Assembly Fiecare este rugat sa publice doar rezultatul , nu si metodele.Nu trebuie sa va inventati rezultatul deoarece executabilul il contine deja.
  4. In acest articol voi vorbi despre memory segmentation.voi defini intrun mod destul de clar cum vine impartita memoria in segmente atunci cand vine creat un executabil.Avand in vedere faptul ca exista mai multe tipuri de memorie pentru a clarifica lucrurile main memory se refera la RAM.In acest tutorial am vorbit despre memorie hysical && Virtual Memory Explained iar aici voi vorbi despre modul in care memoria RAM vine impartita in segmente.Dupa acest tutorial se va putea intelege conceptul de stack si heap.Voi explica doar lucrurile esentiale iar ceea ce e mai complicat il veti intelege dpe parcurs doar daca veti programa in C sau Assembly. Un alt tutorial care va poate fi de ajutor pentru a intelege ceea ce va fi descris aici este Basic GAS AT&T Assembly Syntax [Tutorial] .Daca vati saturat sa auziti de PUSH,POP,ESP,EBP,EIP,STACK,HEAP,BUFFER atunci lasati-o balta deoarece acest tutorial nu e pentru voi. Voi incepe cu urmatoarea definite:Memoria ram vine impartita in segmente pe care le putem definii sectii de memorie.Cand si unde poate fi observat acest lucru?In momentul in care vine scris un executabil datele din codul sursa impreuna cu instructiile vin salvate in memorie.Ei bine fiecare data din executabil vine salvata intro anumita sectie de memorie.La ce ajuta sa cunosti acest lucru?Ei bine raspunsul e simplu , deoarece iti permite sa ai controlul asupra executabilului si a sistemului.Cum? Veti observa si va veti da seama doar daca veti continua sa studiati acest principiu.Voi prezenta sectiile in care poate fi impartita memoria iar in momentul in care voi face un exemplu cu o bucata de cod voi explica unde vine pusa fiecare instructie. RAM ------------- - stack - <-segment de memorie dinamic ------------- - - - - - NULL - <-segment de memorie nealocat - - - - ------------- - heap - <-segment de memorie dinamic ------------- - BSS - <-variabile care nu sunt initializate ------------- - data - <-variabile initializate ------------- - text - <-instructiile executabilului ------------- - - - OS - <- spatiu alocat pentru sistemul operativ - - ------------- Sectiile sau zonele de memorie contin anumite adrese , ceea ce este important sa cunoasteti este faptul ca numerotarea adreselor vine facuta de la valoarea cea mai mare plecand in decrement spre 0 , iar segmentul OS ajunge la prima memoria disponibila in RAM.Inca un aspect important , in momentul in care vin introduse date in segmentul stack acesta incepe sa alocheze spatiu din segmentul NULL , iar cand datele vin extrase elibereaza segmentul NULL, acelasi lucru se intampla cu segmentul Heap, atunci cand vin stocate date acesta va ocupa spatiu in Null.(Note:Am chemat acest segment null dar de fapt nu are nici un nume generic ci e doar un spatiu de memorie care nu e folosit)In momentul in care vine scris un executabil variabilele, functiile si instructiile definite vin stocate in aceste segmente.Aici vom face cateva exemple:Urmatoarul exemplu demonstreaza in care segment vor fi stocate anumite variabile #include<stdio.h> #include <stdlib.h> void function() { int first; //stack printf("Introdu un caracter: "); scanf("%d",&first); printf("[+] int %d (va merge in segmentul stack la adresa addr %p)\x0a",first ,&first); return; } int main() { static int second; // va merge in segmentul BSS static int third = 2; // va merge in segmentul data //int *fourth; // urmatoarea variabila este alocata in segmentul stack dar e un pointer in segmentul heap int *fourth = (int*)malloc(sizeof(int)); //heap int *fifth; // un pointer care merge in segmentul stack printf("[+] int second addr %p (va merge in segmentul bss)\x0a",&second); printf("[+] int third addr %p (va merge in segmentul data)\x0a",&third); printf("[+] int fourth addr %p (va merge in segmentul heap)\x0a",&*fourth); printf("[+] int fifth addr %p (va merge in segmentul stack)\x0a",&fifth); function(); return 0; } Va trebui doar sa compilati si sa executati codul, asadar in output veti putea observa fiecare variabila la care adresa se gaseste si in care segment vine stocata.Dupa cum observati istructiile programului vor fi stocate in segmentul text Contents of section .text: 80483a0 31ed5e89 e183e4f0 50545268 20850408 1.^.....PTRh ... 80483b0 68308504 08515668 98840408 e897ffff h0...QVh........ 80483c0 fff49090 90909090 90909090 90909090 ................ 80483d0 5589e553 83ec0480 3d289804 0800753f U..S....=(....u? 80483e0 a12c9804 08bb2097 040881eb 1c970408 .,.... ......... 80483f0 c1fb0283 eb0139d8 731e8db6 00000000 ......9.s....... 8048400 83c001a3 2c980408 ff14851c 970408a1 ....,........... 8048410 2c980408 39d872e8 c6052898 04080183 ,...9.r...(..... 8048420 c4045b5d c38d7426 008dbc27 00000000 ..[]..t&...'.... 8048430 5589e583 ec18a124 97040885 c07412b8 U......$.....t.. 8048440 00000000 85c07409 c7042424 970408ff ......t...$$.... 8048450 d0c9c390 5589e583 ec28b8e0 85040889 ....U....(...... 8048460 0424e801 ffffffb8 f6850408 8d55f489 .$...........U.. 8048470 54240489 0424e80d ffffff8b 55f4b8fc T$...$......U... 8048480 8504088d 4df4894c 24088954 24048904 ....M..L$..T$... 8048490 24e8d2fe ffffc9c3 5589e583 e4f083ec $.......U....... 80484a0 20c70424 04000000 e8cbfeff ff894424 ..$..........D$ 80484b0 1cb83c86 0408c744 24043098 04088904 ..<....D$.0..... 80484c0 24e8a2fe ffffb874 860408c7 44240424 $......t....D$.$ 80484d0 98040889 0424e88d feffffb8 ac860408 .....$.......... 80484e0 8b54241c 89542404 890424e8 78feffff .T$..T$...$.x... 80484f0 b8d88604 088d5424 18895424 04890424 ......T$..T$...$ 8048500 e863feff ffe84aff ffffb800 000000c9 .c....J......... 8048510 c3909090 90909090 90909090 90909090 ................ 8048520 5589e55d c38d7426 008dbc27 00000000 U..]..t&...'.... 8048530 5589e557 5653e84f 00000081 c3c11200 U..WVS.O........ 8048540 0083ec1c e8bffdff ff8dbb18 ffffff8d ................ 8048550 8318ffff ff29c7c1 ff0285ff 742431f6 .....)......t$1. 8048560 8b451089 4424088b 450c8944 24048b45 .E..D$..E..D$..E 8048570 08890424 ff94b318 ffffff83 c60139fe ...$..........9. 8048580 72de83c4 1c5b5e5f 5dc38b1c 24c39090 r....[^_]...$... 8048590 5589e553 83ec04a1 14970408 83f8ff74 U..S...........t 80485a0 13bb1497 04086690 83eb04ff d08b0383 ......f......... 80485b0 f8ff75f4 83c4045b 5dc39090 ..u....[]... Vom continua cu 2 segmente de memorie importante si anume Stack si Heap ------------- - stack - <-segment de memorie dinamic ------------- - - - - - NULL - <-segment de memorie nealocat - - - - ------------- - heap - <-segment de memorie dinamic ------------- Recapituland , ori de cate ori vor fi stocate date in stack acesta va cobora in jos luand spatiul necesar pentru a stoca aceste date din segmentul NULL, acelasi efect se va intampla daca datele for fi stocate in segmentul heap.Probabil intrebarea voastra este urmatoarea , ce se intampla daca ambele segmente preiau spatiul disponibil din NULL?Ei bine segmentul stack este dinamic iar o data ce datele au fost procesate elibera spatiul din null ,acelasi lucru face si segmentul heap doar ca aici depinde de programator deoarece memoria in acest segment vine alocata prin functia malloc() si vine eliberata folosind functia free()Evident daca careva va aloca o gramada de memorie fara sa fie eliberata folosind-use de segmentul heap vom avea un memory leak.Segmentul stack este divers de heap si o data ce nu mai are nevoie de date va alibera memoria in mod dinamic si automat. Cum functioneaza segmentul stack?In stack vin alocate diverse avariabile in mod dinamic.Spre exemplu daca noi stocam in stack valorile 1,2,3 , pentru a elibera sau extrage valorile se va face in mod invers , si anume prima valoare pe care o vom extrage afara din stack este 3 dupa care 2 si unu.Acest concept vine chemat LIFO (Last In First Out).O mica demonstratie: Avem urmatorul cod: int main() { int var1; //declar o variabila var1 int var2; //declar o variabila var2 int var3; //declar o variabila var3 } Aceste date vin alocate in segmentul stack exact in modul in care au fost declarate si anume: STACK ---------- <-EBP - var1 - ---------- - var2 - ---------- - var3 - ---------- <-ESP Segmentul de stack va creste in jos ocupand spatiu din segmentul NUll Aici voi introduce 2 noi aspecte, in assembly vin folositi doi registrii Registrul ce contine ultima adresa de memorie din stack care se numeste ESP /Extended Stack Pointer), un alt registru ce va contine primul record de memorie din functia sau procedura in care ne aflam si se numeste EBP(Extended Base Pointer)Momentan exista doar o singura functie si anume main. Dupa cum am precizat numerotarea adreselor vine facut de sus in jos in mod invers, nu vom avea niciodata un stack care pleaca de la 0 deoarece intotdeauna in sistem vor exista deja alte processe care se vor folosi de aceste adrese.Asadar presupunem ca in momentul in care vrem sa introducem o valoare in stack ESP se afla la adresa 0xbffff9e8 ,deci pentru a stoca 4 byte in stack va trebui facut un decrement de 4 byte. Deci 0xbffff9e8 - 4 = bffff9e88.Acum ESP se va afla la adresa 0xbffff9e8.De cate ori vine introdusa o valoare vine facut un decrement.Acum in momentul in care eu fac urmatoare operatie matematica si anume bffff9e88 + 4 = 0xbffff9e8 voi sterge 4 byte din stack iar registrl ESP se va afla acum la adresa 0xbffff9e8.Avand in vedere faptul ca pleaca de la ao adresa superioara in decrement spre 0 cand se va face o adunare se vor sterge elemente iar in momentul in care se vor pune elemente se va face un decrement iar adresa stack-ului va creste in jos spre 0.Assembly pune la dispozitie doua instructii pentru a stoca si extrage date din stack, acestea sunt PUSH si POP.PUSH Va stoca o valoare in segmentul stack iar POP va extrage o valoare.Mai exista un aspect foarte important a acestui segment de memorie pe care il voi incerca sa explic cu urmatorul exemplu de cod: #include <stdio.h> int doprint() { printf("Hello\n"); } int main () { doprint(); return 0; } Avem un simplu executabil care chiama o functie care face un print.Vom analiza datele din stack in momentul in care vine chemata functia doprint. Deci in momentul in care vine chemata functia print se intampla acest lucru MAIN chiama doprint 0x080483de <main+6>: call 0x80483c4 <doprint> 0x080483e3 <main+11>: mov $0x0,%eax In acest moment urmatoarea adresa care va trebui sa fie executata dupa ce doprint isi termina treaba va fi stocata in stack ca adresa de return.Can doprint termina treaba se intoarce aici si main continua. Vine pusa valoarea registrului EBP in stack 0x080483c4 <doprint+0>: push %ebp Valoarea EBP 0xbffff9a8 Valoarea actuala din ESP vine pusa in EBP 0x080483c5 <doprint+1>: mov %esp,%ebp In stacK vine facut un decrement de 24 byte pentru a aloca spatiul necesar pentru variabile. 0x080483c7 <doprint+3>: sub $0x18,%esp Note 0x18 este echivalent cu 24 in hex Vin incarcate si stampate datele din functia doprint 0x080483ca <doprint+6>: movl $0x80484b0,(%esp) 0x080483d1 <doprint+13>: call 0x80482f8 <puts@plt> Urmatoarea instructie este importanta deoarece aici functia doprint a terminat treaba si va trebui sa se intoarca in main ca sa termine programul 0x080483d6 <doprint+18>: leave 0x080483d7 <doprint+19>: ret Instructia leave face in asa fel incat registrii ESB si EBP sa isi preia locul initial pe care il aveau inainte sa intre in doprint.Instructia ret va copia adresa 0x080483e3 in EIP asadar procesorul va executa instructtia care se gaseste la aceasta adresa si anume return 0; Stack -------------- - 0x080483e3 - <-Return Address -------------- - EBP (OLD) - -------------- <-EBP - 0xbffff980 - -------------- - 0xbffff990 - -------------- <-ESP In debugger segmentul de stack pentru aceste instructii poate fi reprezentat in acest mod 0xbffff980: 0xb7fc5304 0xb7fc4ff4 0x08048400 0xbffff9a8 0xbffff990: 0xb7eb3365 0xb7ff1040 0xbffff9a8 0x080483e3 Momentan inchei aici tutorialul, voi continua cu alte articole unde voi discuta despre buffer overflow.Daca aveti intrebari , le puteti face.Multe alte lucruri nu au fost explicate pentru a nu pune in confuzie user-ul. Scopul acestui tutorial era sa explice faptul ca memoria poate fi impartita in segmente si ca in aceste segmente pot fi stocate diverse date.
  5. Reversing the bomb Acest tutorial are ca scop o introducere in domeniul reversing , aici voi discuta despre modul in care poate fi schimbat fluxul unui program.In acelasi timp va fi si un raspuns pentru challenge-ul pe care l-am creat .Vom avea urmatorul exemplu:Un program in care user-ului i se cere o cheie pentru a putea schimba fluxul , in acelasi timp se presupune ca user-ul nu poate ghici care este aceasta cheie sau serial.Vom lua executabilul bomb32 si il vom analiza.Vom folosi urmatoarele tool-uri pentru a face aceasta inspectie: Un debugger , eu prefer gdb dar poate fi oricare altul.Un Hex editor , voi folosi bvi dar exista diverse altele cu interfata grafica precum bless , okteta sau wxHexEditor.In acest articol voi folosi objdump si nm . Tin sa precizez faptul ca nu intotdeauna se pot extrage unele informatii folosind objdump sau nm.In urmatorul exemplu vom vedea sectiile create in acest executabil. [pyth0n3@mc]$ nm bomb 080491e0 A __bss_start 080491e0 A _edata 080491e0 A _end 08048081 T _start 0804919e d arm 08048085 t armed 080490f4 d buf 00000095 a bufl 08049174 d bufs 08049189 d dis 080480c6 t disarm 080491b1 d do 080480d8 t explode 080480e8 t out 08048074 t print 080480bb t wires Folosind un debugger vom putea pune un breakpoint si analiza fiecare sectie , dar inainte vom dezasabla fiecare sectie de cod folosind objdump [pyth0n3@mc]$ objdump -S bomb bomb: file format elf32-i386 Disassembly of section .text: 08048074 <print>: 8048074: b8 04 00 00 00 mov $0x4,%eax 8048079: bb 01 00 00 00 mov $0x1,%ebx 804807e: cd 80 int $0x80 8048080: c3 ret 08048081 <_start>: 8048081: 90 nop 8048082: 90 nop 8048083: 90 nop 8048084: 90 nop 08048085 <armed>: 8048085: 8d 0d 9e 91 04 08 lea 0x804919e,%ecx 804808b: ba 13 00 00 00 mov $0x13,%edx 8048090: e8 df ff ff ff call 8048074 <print> 8048095: 8d 0d b1 91 04 08 lea 0x80491b1,%ecx 804809b: ba 2f 00 00 00 mov $0x2f,%edx 80480a0: e8 cf ff ff ff call 8048074 <print> 80480a5: b8 03 00 00 00 mov $0x3,%eax 80480aa: bb 00 00 00 00 mov $0x0,%ebx 80480af: b9 f4 90 04 08 mov $0x80490f4,%ecx 80480b4: ba 95 00 00 00 mov $0x95,%edx 80480b9: cd 80 int $0x80 080480bb <wires>: 80480bb: 31 c0 xor %eax,%eax 80480bd: 3d 09 03 00 00 cmp $0x309,%eax 80480c2: 75 14 jne 80480d8 <explode> 80480c4: cd 80 int $0x80 080480c6 <disarm>: 80480c6: 8d 0d 89 91 04 08 lea 0x8049189,%ecx 80480cc: ba 16 00 00 00 mov $0x16,%edx 80480d1: e8 9e ff ff ff call 8048074 <print> 80480d6: eb 10 jmp 80480e8 <out> 080480d8 <explode>: 80480d8: 8d 0d 74 91 04 08 lea 0x8049174,%ecx 80480de: ba 15 00 00 00 mov $0x15,%edx 80480e3: e8 8c ff ff ff call 8048074 <print> 080480e8 <out>: 80480e8: b8 01 00 00 00 mov $0x1,%eax 80480ed: bb 00 00 00 00 mov $0x0,%ebx 80480f2: cd 80 int $0x80 Voi comenta fiecare sectie pentru a avea o idee putin mai clara.Aici vine declarata o functie care va stampa pe ecran valori (momentan a fost doar declarata functia , dar poate fi chemata in alte sectii) Daca ati citit articolul pe care l-am scris despre assembly veti putea interpeta fiecare valoare care vine pusa in registrii. 08048074 <print>: 8048074: b8 04 00 00 00 mov $0x4,%eax 8048079: bb 01 00 00 00 mov $0x1,%ebx 804807e: cd 80 int $0x80 8048080: c3 ret De la sectia start incepe executarea programului iar 4 valori chemate nop nu fac absolut nimic .In sectia armed vin incarcate cateva valori in registri dupa care vine chemata functia print care nu face altceva decat sa stampeze aceste valori pe ecran. 08048081 <_start>: 8048081: 90 nop 8048082: 90 nop 8048083: 90 nop 8048084: 90 nop 08048085 <armed>: 8048085: 8d 0d 9e 91 04 08 lea 0x804919e,%ecx 804808b: ba 13 00 00 00 mov $0x13,%edx 8048090: e8 df ff ff ff call 8048074 <print> 8048095: 8d 0d b1 91 04 08 lea 0x80491b1,%ecx 804809b: ba 2f 00 00 00 mov $0x2f,%edx 80480a0: e8 cf ff ff ff call 8048074 <print> 80480a5: b8 03 00 00 00 mov $0x3,%eax 80480aa: bb 00 00 00 00 mov $0x0,%ebx 80480af: b9 f4 90 04 08 mov $0x80490f4,%ecx 80480b4: ba 95 00 00 00 mov $0x95,%edx 80480b9: cd 80 int $0x80 Pentru a analiza exact ce vine facut in aceasta sectie vom folosi gdb (gdb) break armed Breakpoint 1 at 0x8048085 (gdb) run Starting program: /home/pyth0n3/Desktop/bomb Breakpoint 1, 0x08048085 in armed () (gdb) s Single stepping until exit from function armed, which has no line number information. 0x08048074 in print () (gdb) s Single stepping until exit from function print, which has no line number information. [COLOR="#00FF00"]Bomb Armed ______ 0x08048095 in armed ()[/COLOR] (gdb) s Single stepping until exit from function armed, which has no line number information. 0x08048074 in print () (gdb) s Single stepping until exit from function print, which has no line number information. [COLOR="#00FF00"]Disarm the bomb by cutting the correct wires > 0x080480a5 in armed ()[/COLOR] (gdb) s Single stepping until exit from function armed, which has no line number information. [COLOR="#00FF00"]Aici vine cerut un input [/COLOR] Am pus un breakpoint in sectia armed dupa care am rulat programul si am vazut ce face in fiecare step.Am evidentiat in culoare verde ceea ce vine executat in aceasta sectie.Dupa cum observati vin stampate cateva informatii si vine cerut un input de la user.Vom merge mai departe sa analizam urmatoarea sectie. 080480bb <wires>: 80480bb: 31 c0 xor %eax,%eax 80480bd: 3d 09 03 00 00 cmp $0x309,%eax 80480c2: 75 14 jne 80480d8 <explode> 80480c4: cd 80 int $0x80 080480c6 <disarm>: 80480c6: 8d 0d 89 91 04 08 lea 0x8049189,%ecx 80480cc: ba 16 00 00 00 mov $0x16,%edx 80480d1: e8 9e ff ff ff call 8048074 <print> 80480d6: eb 10 jmp 80480e8 <out> 080480d8 <explode>: 80480d8: 8d 0d 74 91 04 08 lea 0x8049174,%ecx 80480de: ba 15 00 00 00 mov $0x15,%edx 80480e3: e8 8c ff ff ff call 8048074 <print> Imediat dupa armed vine executata sectia wires .Vom analiza fiecare instructie.xor %eax,%eax nu face altceva decat sa puna valoarea 0 in registrul eax. cmp $0x309,%eax compara numarul 777 cu registrul eax.309 in hex este echivalent cu 777.In eax avem valoarea 0 datorita instructiei precedente.Deci vine comparat 777 cu 0 , asadar aceste 2 valori nu sunt egale deci este fals deoarece 777 nu este egal cu 0.Urmatoarea instructie va fi executata in baza rezultatului acestei instructii si anume jne va face un jump in urmatoarea adresa de memorie 80480d8 daca valorile in urma comparatiei nu sunt egale .Cum am mai spus 777 nu este ega cu valoarea din eax asadar se va face un jump .Dupa cum observati la adresa 80480d8 incepe sectia <explode>.In acest caz imediat dupa instructia jne va fi executata aceasta sectie.Tin sa precizez faptul ca in momentul in care comparatia ar fi fost adevarata si anume valoarea din eax ar fi fost 777 atunci 777 este egal cu 777 si instructia jne nu va mai face un jump in sectia explode ci va fi executata urmatoarea instructie imediat dupa.jne face un jump atata timp cat valorile care au fost comparate in instructia precedenta nu sunt egale in mod divers vine executata urmatoarea instructie dupa jne.Evident datele nu au fost alterate dupa input asadar se va face un jump in explode iar sectia disarm nu va fi executata.Ia sa vedem ce se intampla in explode.Am incarcat executabilul in gdb dupa care am pus un breakpoint in sectia explode (gdb) break explode Breakpoint 1 at 0x80480d8 (gdb) run Starting program: /home/pyth0n3/Desktop/bomb [COLOR="#00FF00"]Bomb Armed ______ Disarm the bomb by cutting the correct wires > test [/COLOR] Breakpoint 1, 0x080480d8 in explode () (gdb) s Single stepping until exit from function explode, which has no line number information. 0x08048074 in print () (gdb) s Single stepping until exit from function print, which has no line number information. [COLOR="#00FF00"]***BOOM! You Failed![/COLOR] 0x080480e8 in out () (gdb) s Single stepping until exit from function out, which has no line number information. [COLOR="#00FF00"]Program exited normally.[/COLOR] Asadar programul va fi rulat, userului ii vine cerut un input , am pus "test" dupa care ajungem direct in sectia explode unde am facut un breakpoint.Dupa cum observati instructiile din sectia explode stampeaza niste informatii dupa care programul vine terminat.Deci pana aici am observat ca nu vine facut nici un control asupra datelor pe care le-am introdus.(am scris programul in acest fel pentru a explica faptul ca oricare ar fi input-ul user-ului nu exista nici o probabilitate sa coincida cu serialul sau cu cheia pentru a dezarma bomba.) Acum daca nu s-ar fi facut un jump in sectia explode s-ar fi executat intructiile exact dupa sectia wires si anume disarm. 080480bb <wires>: 80480bb: 31 c0 xor %eax,%eax 80480bd: 3d 09 03 00 00 cmp $0x309,%eax 80480c2: 75 14 jne 80480d8 <explode> 80480c4: cd 80 int $0x80 Ei bine ca sa fie executate aceste intructii valoarea care vine confruntata cu eax trebuie sa fie egala cu valoarea din eax.Acest lucru poate fi doar cazual in momentul in care eax dintro oarecare greseala ar fi avut valoarea 777 dar este si imposibil deoarece urmatoarea instructie va pune 0 in eax xor %eax,%eax.Daca nu ar fi existat xor o probabilitate ar fi ca eax sa aiba alta valoare dar nu este confirmat ca aceasta valoare ar fi fost egala cu 777.Asadar nu cunoastem serialul dar stim ca daca valorile confruntate nu sunt egale vine facut un jump in sectia explode si vin executate instructiile de acolo.Hai sa vedem ce face sectia disarm care nu vine executata niciodata. (gdb) disas disarm Dump of assembler code for function disarm: 0x080480c6 <disarm+0>: lea 0x8049189,%ecx 0x080480cc <disarm+6>: mov $0x16,%edx 0x080480d1 <disarm+11>: call 0x8048074 <print> 0x080480d6 <disarm+16>: jmp 0x80480e8 <out> End of assembler dump. (gdb) x/20cb 0x8049189 0x8049189 <dis>: 66 '[COLOR="#00FF00"]B[/COLOR]' 111 '[COLOR="#00FF00"]o[/COLOR]' 109 '[COLOR="#00FF00"]m[/COLOR]' 98 '[COLOR="#00FF00"]b[/COLOR]' 32 ' ' 68 '[COLOR="#00FF00"]D[/COLOR]' 105 '[COLOR="#00FF00"]i[/COLOR]'115 '[COLOR="#00FF00"]s[/COLOR]' 0x8049191 <dis+8>: 97 '[COLOR="#00FF00"]a[/COLOR]' 114 '[COLOR="#00FF00"]r[/COLOR]' 109 '[COLOR="#00FF00"]m[/COLOR]' 101 '[COLOR="#00FF00"]e[/COLOR]' 100 '[COLOR="#00FF00"]d[/COLOR]' 32 ' ' 95 '_' 95 '_' 0x8049199 <dis+16>: 47 '/' 32 ' ' 95 '_' 95 '_' Dupa cum observati vin incarcate in eax datele de la adresa 0x8049189 si anume "Bomb Disarmed __/ __" dupa care vine chemata functia print care le stampeaza si se face un jump in out care e urmatoarea sectie 080480e8 <out>: 80480e8: b8 01 00 00 00 mov $0x1,%eax 80480ed: bb 00 00 00 00 mov $0x0,%ebx 80480f2: cd 80 int $0x80 Aici programul iese.Acum am observat care sunt datele in sectia disarm , am observat faptul ca nu vine executata aceasta sectie.Pentru a rezolva problema nu ne ramane decat sa facem in asa fel incat sectia disarm sa fie executata.CUM?Pentru ca aceasta sectie sa fie executata valorile care vin comparate trebuie sa fie egale sau sa nu fie executata instructia jne.Deci va trebui lucrat asupra sectiei wires deoarece aici vine facut controlul asupra fluxului: 080480bb <wires>: 80480bb: 31 c0 xor %eax,%eax 80480bd: 3d 09 03 00 00 cmp $0x309,%eax 80480c2: 75 14 jne 80480d8 <explode> 80480c4: cd 80 int $0x80 1. Putem modifica valoarea care vine comparata cu eax in asa fel incat sa fie 0 asadar 0==0 si instructia jne nu va face un jump ci se vor executa urmatoarele instructii si anume sectia disarm.Va trebui doar sa modificam valoarea 777 cu 0 , acest lucru se poate face cu un hex editor. 0x080480bb in wires () (gdb) (gdb) disas wires Dump of assembler code for function wires: 0x080480bb <wires+0>: xor %eax,%eax 0x080480bd <wires+2>: cmp $[COLOR="#00FF00"]0x309[/COLOR],%eax 0x080480c2 <wires+7>: jne 0x80480d8 <explode> 0x080480c4 <wires+9>: int $0x80 End of assembler dump. (gdb) x/4bx wires+2 0x80480bd <wires+2>: 0x3d [COLOR="#00FF00"]0x09 0x03[/COLOR] 0x00 (gdb) Asadar daca modificam urmatoarele valori 09 03 cu 00 00 programul isi va schimba fluxul deoarece comparatia va da True deoarece 0 este egal cu 0 00000090 E8 DF FF FF FF 8D 0D B1 91 04 08 BA 2F 00 00 00 ............/... 000000A0 E8 CF FF FF FF B8 03 00 00 00 BB 00 00 00 00 B9 ................ 000000B0 F4 90 04 08 BA 95 00 00 00 CD 80 31 C0 3D [COLOR="#00FF00"]09 03[/COLOR] ...........1.=.. 000000C0 00 00 75 14 CD 80 8D 0D 89 91 04 08 BA 16 00 00 ..u............. 000000D0 00 E8 9E FF FF FF EB 10 8D 0D 74 91 04 08 BA 15 ..........t.... 2. Putem modifica instructia jne cu nop (care este echivalent la no operation performed) asadar nu va face jump deoarece nop nu face nimic si va fi executata urmatoarea instructie care apartine sectiei disarm.Va trebui doar sa gasim valoarea care corespunde instructiei jne in hex si sa o modificam.Acest lucru poate fi facut folosind gdb. Dump of assembler code for function wires: 0x080480bb <wires+0>: xor %eax,%eax 0x080480bd <wires+2>: cmp $0x309,%eax 0x080480c2 <wires+7>: [COLOR="#00FF00"]jne [/COLOR] 0x80480d8 <explode> 0x080480c4 <wires+9>: int $0x80 End of assembler dump. (gdb) x/4bx wires+7 0x80480c2 <wires+7>:[COLOR="#00FF00"] 0x75 0x14[/COLOR] 0xcd 0x80 (gdb) Dupa cum observati una din valori sau poate chiar 2 pot apartine instructiei jne .exlud ultima 0x80 si penultima deoarece instructia e la inceput asadar verific 75 si 14 000000B0 F4 90 04 08 BA 95 00 00 00 CD 80 31 C0 3D 09 03 ...........1.=.. 000000C0 00 00 [COLOR="#00FF00"]75 14[/COLOR] CD 80 8D 0D 89 91 04 08 BA 16 00 00 ..u............. 000000D0 00 E8 9E FF FF FF EB 10 8D 0D 74 91 04 08 BA 15 ..........t..... 000000E0 00 00 00 E8 8C FF FF FF B8 01 00 00 00 BB 00 00 ................ 000000F0 00 00 CD 80 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ Aici se afla instructia jne pe care o vom inlocui cu nop , nop in hex e 90 si va trebui sa inlocuim 2 B asadar vom pune 90 90 in locul 75 14. Problem solved.! [pyth0n3@mc]$ ./bomb Bomb Armed ______ Disarm the bomb by cutting the correct wires > test Bomb Disarmed __/ __ Puteti testa fiecare ceea ce am descris mai sus.Cum am ajuns la problema? Simplu , verificand structurele de control conditionat sau inconditionat.Pentru mai multe informatii in legatura cu instructiile care pot schimba fluxul X86 Assembly/Control Flow In momentul in care exista un program care cere un serial sau un cod , va exista intotdeauna o instructie care ii poate schimba fluxul, trebuie doar gasita si modificata.Challenge-ul a fost rezolvat de catre Flubber si em, DarkyAngel a individuat problema dar era confuz asupra valorilor, nu am mai primit raspuns. Codul l-am scris doar pentru a demonstra cum functioneaza structurele de control in asembly sintaxa e AT&T Gas ISA Intel 32 biti .data buf: .space 0x80 bufs: .ascii "***BOOM! You Failed!\n" bufl= .-buf dis: .ascii "Bomb Disarmed __/ __\n" arm: .ascii "Bomb Armed ______ \n" do: .ascii "Disarm the bomb by cutting the correct wires\n> " .text #.global main .globl _start .type print, @function print: movl $4, %eax movl $1, %ebx int $0x80 ret #main: _start: nop nop nop nop armed: leal arm,%ecx movl $0x13, %edx call print leal do,%ecx movl $0x2F,%edx call print movl $0x3,%eax movl $0x0,%ebx movl $buf,%ecx movl $bufl,%edx int $0x80 wires: xorl %eax, %eax cmp $0x309,%eax jne explode int $0x80 disarm: leal dis,%ecx movl $0x16, %edx call print jmp out explode: leal bufs,%ecx movl $0x15, %edx call print out: movl $0x1,%eax movl $0x0,%ebx int $0x80 Am tradus codul si pentru arhitectura Intel 64 bit , sintaxa e tot AT&T Gas .data buf: .space 0x80 bufs: .ascii "***BOOM! You Failed!\n" bufl= .-buf dis: .ascii "Bomb Disarmed __/ __\n" arm: .ascii "Bomb Armed ______ \n" do: .ascii "Disarm the bomb by cutting the correct wires\n> " .text #.global main .globl _start .type print, @function print: movq $0x1, %rax movq $0x1, %rdi syscall retq _start: nop armed: movq $arm,%rsi movq $0x13, %rdx call print movq $do,%rsi movq $0x2E,%rdx call print movq $0x0,%rax movq $0x0,%rdi movq $buf,%rsi movq $bufl,%rdx syscall wires: xor %rax, %rax cmp $0x309,%rax jne explode syscall disarm: movq $dis,%rsi movq $0x15, %rdx call print jmp out explode: movq $bufs,%rsi movq $0x15, %rdx call print out: movq $0x3C,%rax movq $0x0,%rdi syscall
  6. In acest tutorial voi descrie caracteristicile de baza a limbajului de programare assembly.Vom avea un simplu exemplu de baza si anume stamparea unei variabile in stdout, structura instructiilor , definirea sectiunilor de baza , memoria, registrii de baza care pot fi intalniti in arhitectura procesoarelor de 32 biti Intel , nu in ultimul rand voi converti un exemplu de cod assembly scris pentru arhitectura intel 32 biti in 64 biti.Voi folosi cei mai simpli termeni pentru a descrie structura instructiilor si a unui registru.Pentru a nu duce in erroare un user ma voi folosi doar de registrii indispensabili.Assembly este un limbaj de programare Low Level.Spre deosebirea celorlalte limbaje de programare assembly necesita o traducere simpla in Machine Code deoarece fiecare cuvant sau mai bine spus instructie in assembly vine transformata intro instructie macchine code.Intructiile in machine code sunt intructii binare care pot fi interpretate foarte simplu de catre un computer dar putin mai greu de catre o persoana.De aceea pentru fiecare instructie binara a fost creata o instructie in assembly care poate fi denumita human readable deoarece creierului uman este mai simplu sa memoreze un anumit alias decat o instructie in 0 si 1.Fiecare procesor are un set de instructii assembly care difera de la o arhitectura la alta.Pentru a traduce instructiile assembly in operation code (macchine instruction code) vine folosit un traducator chemat assembler.Acesta este un software care interpreteaza instructiile scrise in assembly si le traduce in macchine code.Ei bine exista mai multe tipuri de assembler si fiecare are o anumita sintaxa.Instructiile scrise de catre un anumit assembler nu pot fi traduse in opcode de catre alt tip de assembler deoarece instructiile sunt diverse.Cele mai cunoscute tipuri de assembler sunt urmatoarele: NASM Windows, Linux, Mac OS X, DOS, OS/2 MASM Windows, DOS, OS/2 TASM Windows, DOS Yasm Windows, DOS, Linux, Unix-like HLA Windows, Linux, FreeBSD, Mac OS X GAS Unix-like, Windows, DOS, OS/2 Evident lista poate fi mult mai lunga , dar ma limitez aici.Ceea ce este important sa intelegeti este faptul ca fiecare are o sintaxa particulara pentru a scrie intructiile si ca exista diverse moduri de a programa in assembly.Pentru acest tutorial si urmatoarele exemple eu voi folosi GAS ca assembler.Ce este important sa cunoasteti este ca acest tip de assembler permite scrierea instructiilor assembly in 2 moduri.De default este folosita sintaxa AT&T dar poate fi folosita si sintaxa Intel.Ambele sintaxe pot traduce instructiile in opcode compatibil cu procesoarele Intel doar ca difera modul in care sunt scrise instructiile. Intex Syntax instructie dest,source AT&T Syntax instructie source,dest In urmatoarele exemple voi folosi doar AT&T Syntax.Assembly nu este un limbaj de programare cross platform deci anumite instructii vor putea fi executatea doar pe anumite platforme si nu pe altele.Exemplele sunt create pentru sistemele Linux 32 Biti Intel.In final voi traduce exemplul din tutorial si pentru arhitectura Intel 64 biti Linux.De obicei limbajele de programare se invata intrun anumit mod .Vin invatate structurele de date, instructiile , structurele de control , functiile si cu putina practica o persoana poate incepe sa programeze.Ei bine in assembly este putin diverssi pentru a obtine o anumita functie vor trebui scrise mai multe linii de cod.Pentru a cunoaste assembly necesita cunostinta sistemului operativ, a structurii procesorului si cum vine alocata memoria in ambientul respectiv.Acest tutorial este basic deoarece am vrut sa merg pe principul keep it simple .Vom incepe cu descrierea arhitecturii a unui computer.Avem un procesor , 3 tipuri de memorie (cache memory, main memory , secondary memory) ,Input/Output Devices (tastiera spre exemplu).Procesorul acceseaza date in memorie in urmatorul fel:Va cauta in mod direct existenta datelor in cache memory , main memory(ram) si in mod indirect date in secondary memory (hard disk).In cazul in care datele nu se gasesc in casche memory sau in main memory vor fi incarcate din secondary memory in main memory dupa care procesorul va avea access direct la ele.Conceptul programarii in assembly este urmatorul: Procesorul preia date din memorie executa operatii aritmetice asupra datelor si stocheaza rezultatul inapoi in memorie sau il stampeaza in stdout (monitorul user/ului).La randul lor datele pot fi preluate din stdin (tastiera) , pot fi procesate si stocate in memorie sau pe ecranul user-ului.In momentul in care datele vin preluate de catre cpu din main memory(ram) pentru a executa anumite operatii asupra lor vin stocate intrun alt spatiu de memorie, acest spatiu vine chemat registu.Un cpu detine mai multi registrii pentru a stocain mod temporar datele atunci cand se fac operatii asupra lor dupa care datele vin puse la locul de unde au fost luate .Ceea ce probabil il pune pe user intro stare de umra este faptul ca procesorul poate detine multi registrii.Nu e nevoie sa cunosti fiecare registru daca nu il folosesti atunci cand programezi in assembly .In acest articol nu voi descrie toti registrii deoarece voi crea o confuzie.Ceea ce este important sa cunoasteti este faptul ca atunci cand o valoare este preluata din memorie trebuie stocata intrun anumit loc temporar unde pentru a face operatii asupra ei dupa care rezultatul va fi stocat inapoi in memorie iar registrul temporar va prelua urmatoarea valoare. Ca in fiecare limbaj de programare si in assembly programul vine impartit in anumite sectii.Exista o sectie unde pot fi declarate anumite tipuri de date.Spre exemplu exista o sectie chemata .data , aici pot fi declarate tipurile de date cu care se va lucra, Aceasta sectie poate fi paragonata cu declararea variabilelor in alte limbaje de programare. O alta sectie este .bss , in aceasta sectie se pot declara alte tipuri de date a caror valoare spre exemplu nu este cunoscuna initial.O alta sectie este .text , aici pot fi scrise instructiile care vor procesa datele declarate si procesate in sectiile .data .bss.O alta sectie importanta este .globl , aici pot fi chemate functii/librari externe care au fost deja create in precedenta.Vom avea si o sectie _start de unde instructiile vor incepe sa fie executate.Aceasta sectie poate fi paragonata cu functia main() in c. Pentru a scrie un simplu program in assembly se vor crea sectiile respective, se vor umple cu date dupa care se vor chema instructii asupra datelor declarate.In urmatoarele exemple vom vedea cum se pot declara date , cum vin declarate instructiile? , ce se intampla atunci cand instructiile vin traduse in opcode?, cum vin incarcate datele din memorie intrun registru?, cum pot fi chemate functii externe asupra datelor? Pentru a putea face o operatie asupra unei valori , va trebui declarata valoarea respoectiva , acelasi lucru si pentru oricare alt tip de date.Initial vom construi o sectie .data unde vom stoca un nickname. Declar o sectie data in memorie .data Declar o eticheta pentru tipul de date pe care il voi crea NickName: Declar tipul de date pe care vreau sa le stochez in memorie .ascii "pyth0n3\n: Asadar am creat o sectie, o eticheta , un tip de date Eticheta va avea o adresa in memoria RAM , la adresa respectiva se vor gasi datele pe care le-am declarat Etichetei ii vine atribuita o adresa de memorie NickName data variable address 0x8049098 La adresa 0x8049098 vom avea datele stocate si anume pyth0n3\n NickName data variable content in excaped hex 0x70 0x79 0x74 0x68 0x30 0x6e 0x33 0x0a p y t h 0 n 3 \n Evident o data ce instructia .ascii "pyth0n3\n" va fi tradusa in opcode de catre assembler vom avea urmatorul cod Nick Name data variable content in binary giant, 8 bytes 0000101000110011011011100011000001101000011101000111100101110000 Important este sa intelegeti faptul ca acest cod se afla la o anumita adresa si anume la 0x8049098 ,am tradus adresa in hex dar pentru procesor va fi tot o valoare in 0 si 1.Dupa ce am declarat datele ramane sa decidem ce vrem sa facem cu ele .Vom stampa pe ecran ceea ce am stocat la adresa 0x8049098.Evident pentru a face acest lucru exista mai multe alternative.In Linux ne putem folosi de syscall.Trebuie individuate functiile de care avem nevoie pentru a stampa datele + functia pentru a inchide programul.Fiecare syscall are un anumit id numeric .In fiecare sistem linux lista se poate gasi in /usr/include/asm .In fisierul unistd_32.h se vor gasi functiile pentru procesoarele 32 biti iar in unistd_64.h pentru procesoarele 64 biti.Vom folosi 2 syscall diverse 1 pentru a stampa datele declarate 2 pentru a iesi din program. Pentru a stampa datele vom folosi #define __NR_write care are ca id numarul 4 Pentru a iesi din program vom folosi #define __NR_exit care are ca id numarul 1 Datele care vin procesate trebuie incarcate in registrii asadar vom folosi 4 registrii a procesorului pentru a stoca temporar date care vor fi executate.Asadar vom folosi EAX,EBX,ECX,EDX care pot fi paragonate cu 4 variabile temporare unde vom stoca date care trebuie executate. In momentul in care nu am specificat nici o instructie registrii momentan nu au nici o valoare eax 0x0 0 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 Probabil va intrebati in care ordine pot fi introduse datele in registrii spre exemplu care este primul registru? Ei bine ordinea este urmatoarea EAX EBX ECX EDX.Vom muta valoarea functiei write in primul registru Pentru a scrie instructiile trebuie creata o sectie .text , avand in vedere oricum faptul ca vom chema si functii externe syscall va trebui specificata si o sectie pentru external routines si anume .globl _start dupa care vom crea sectia _start unde vom incepe sa executam instructiile pe care le vom scrie Asadar vom incepe cu prima instructie .text .globl _start _start movl $4, %eax Dupa executarea acestei instructii registrul EAX va avea valoarea 4 eax 0x4 4 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 Functia write are nevoie de cateva argumente pentru a stampa datele si anume primul argument pe care va trebui sa il specificam functiei dupa ce a fost incarcata in registrul EAX este unde anume vrem sa stampam datele? In linux exista 3 tipuri de fisiere chemate file descriptor Standard input identificat de catre valoarea 0 acet fisier preia input-ul de la tastiera spre exemplu Standard output identificat de catre valoarea 1 , acest file este folosit pentru a stampa informatia Standard error indenbtificat de catre valoarea 2, acest file este folosit pemtru a stampa mesajele de erroare. Pentru a stampa datele vom folosi standard output, asadar primul argument va fi specificat in al doilea registru si anume EBX , standard output are ca valoare 1 asadar urmatoarea instructie pe care o vom scrie este movl $1, %ebx Acum registrii au urmatoarele valori eax 0x4 4 ecx 0x0 0 edx 0x0 0 ebx 0x1 1 Al doilea parametru a functiei care trebuie specificat este adresa in memorie unde se afla datele pe care vrem sa la stampam.In urmatorul registru vom incarca adresa etichetei cu urmatoarea instructie leal NickName, %ecx Asadar registrii vor avea urmatoarele valori eax 0x4 4 ecx 0x8049098 134516888 edx 0x0 0 ebx 0x1 1 Dupa cum observati instructia leal NickName, %ecx a incarcat in ECX adresa unde se afla datele si anume 0x8049098 care este echivalent cu 134516888 in decimal.Al treilea argument al functiei care trebuie incarcat in urmatorul registru si anume EDX este lungimea pe care vrem sa o stampam din datele pe care le/am declarat (lungimea nickname-ului este pyth0n3 7+1 newline). movl $8, %edx In acest moment registrii vor avea urmatoarele date eax 0x4 4 ecx 0x8049098 134516888 edx 0x8 8 ebx 0x1 1 Deci pana aici i-am spus procesorului sa faca urmatorul lucru.Mergi la adresa 0x8049098 si stampeaza pe ecran urmatoarele 8 caractere.Daca am fi specificat mai multe caractere ar fi stampat ceea ce se afla dupa 8 caractere pe care le-am declarat in memorie(incercati, o sa va stampeze garbage).In momentul in care instructiile au fost declarate ,nu ramane decat sa chemam procesorul ca sa execute ceea ce am facut pana acum.Urmatoarea instructie va face acest lucru , este un interupt (kernelul va trimite un semnal procesurului ca sa execute ceea ce a fost incarcat in registrii acum. int 0x80 O data ce aceasta instructie vine executata , vor fi stampate pe ecran 8 caractere din datele declarate.(ultimul caracter este doar un newline).Dupa ce datele vor fi stampate registrii vor avea urmatoarele valori eax 0x8 8 ecx 0x8049098 134516888 edx 0x8 8 ebx 0x1 1 Dupa cum observati valoarea din registru EBX este in EAX acum.Dupa ce codul vine executat se va face un return in EAX.Acum nu ramane decat sa declaram instructiile necesare pentru a iesi din program , asadar vom folosi ca syscall exit care are valoarea 1.Dupa cum am specificat , ordinea pentru a incarca instructiile in registrii este urmatoarea .Prima valoare in EAX , iar urmatorii parametrii in EBX,ECX,EDX.Atentie acest lucru este valabil doar pentru procesoarele intel 32 biti.Deci vom chema valoare 1 in registrul EAX. movl $1, %eax Asadar vom avea urmatoarele valori eax 0x1 1 ecx 0x8049098 134516888 edx 0x8 8 ebx 0x1 1 Dupa cum observati registrii nu au fost modificati si unele valori pe care le-am incarcat inainte au ramas in registrii.Atunci cand veti scrie cod putin mai complicat in assembly va trebui sa aduceti registrul la statul initial sau uneori sa daceti un decrement dealtfel registrul va detine valoarea care a fost incarcata initial. Urmatorul parametru pentru functia exit este un return code.Aici putem specifica modul in care vrem sa iesim din program.Un return cod 0 va iesi curat , se poate specifica un return code 1 cand vrem sa iesim cu o erroare. In cazul nostru nu exista o erroare , asadar vom iesi cu 0.Primul si singurul parametru al functiei exit va fi 0. movl, $0 %ebx Dupa cum observati instructiile pe care le-am declarat au fost executate si valorile au fost urcate in registrii EAX va avea valoarea 1 , EBX va avea valoarea 0 iar restul registrilor vor avea valorile precedente eax 0x1 1 ecx 0x8049098 134516888 edx 0x8 8 ebx 0x0 0 Pentru a executa ceea ce este acum in EAX va trebui sachemam un inerrupt , acest semnal va spune procesorului sa execute ce gaseste acum in EAX.Nu vor fi executate datele din registrul ECX si EDX deoarece valoarea pe care am puso in registrul EAX si este echivalenta cu functia exit chiama doar un singur parametru si anume 0 pe care l-am pus in registrul EBX .Asadar vor fi executate datele din EAX SI EBX int $0x80 In acest caz am iesit din program , nu mai vine nimic stampat pe ecran , dar totusi putem observa cu care exist status am iesit.In Linux se poate face acest lucru folosind urmatorul comand imediat dupa ce am executat un program. echo $? In acest tutorial am facut un simplu exemplu in assembly si am observat ce se intampla atunci cand fiecare instructie vine executata. Acest lucru poate fi facut cu un debugger,asadar nu uitati sa asablati codul cu extensii pentru debugging daca vreti sa vedetice face pentru a asambla codul se vafolosi as. as -ggstabs nickname.s -o nickname.o Note: Am specificat optiunea ggstabs doar pentru debugging ,asadar il puteti urca intrun debugger preferat ca sa observati cum vin alocate datele.In momentul de fata vom avea un objec code nickname.o care trebuie ytrecut prin linker.Vom folosi ld pentru linking , asadar vom crea un executabil. ld nickname.o -o nickname Evident in momentul in care il veti trece in debugger veti observa mai multi registrii.Eu m-am limitat ca sa nu duc in erroare.Fiecare registru are rolul lui si fiecare registru este necesar.Un simplu exemplu pe care il veti pbserva atunci cand si doar daca veti face debugging este urmatorul.Presupunem ca am creat un breakpoint inainte ca prima instructie sa fie executata si vrem sa observam valorile care sunt stocate in momentul de fata in registrii.Atentie nu in fiecare registru trebuie neaparat sa existe valori, unii vor avea un flag sau nici o valoare. eax 0x0 0 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 esp 0xbffff840 0xbffff840 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x8048074 0x8048074 <_start> eflags 0x200212 [ AF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0 Dupa cum observati unii registrii au anumite valori precum registrul ESP care va avea intotdeuna o adresa de memorie si anume adresa dintyrun anumit segment de memorie chemat stack (probabil este interesant atunci cand se va scrie un exploit , stack overflow spre exemplu sau buffer overflow).EIP va detine intotdeuna adresa din top a segmentului de memorie chemat stack.Un alt registru inportant este EIP care este un instruction pointer , acest registru va detine intoteauna urmatoarea adresa urmatoarei sintructii care trebuie executate.Sa nu uitam faptul ca si instructiile pe care le folosim trebuie sa fie stocate undeva in memorie.Pentru acest tutorial ma voi opri aici deoarece in momentul de fata nu am folosit alti registrii pentru a putea explica ceea ce fac.Va las exemplele codului din acest tutorial si nu in ultimul rand pentru cai care sunt curiosi voi traduce codul assembly 32 bit in 64 bit doar ca sa observati diferentele. #nickname.s 32 bit intel gas AT&T syntax assembly .data NickName: .ascii "pyth0n3\n" .text .globl _start _start: movl $4, %eax movl $1, %ebx leal NickName, %ecx movl $24, %edx int $0x80 movl $1, %eax movl $0, %ebx int $0x80 #nickname.s 64 bit intel gas AT&T syntax assembly .data NickName: .ascii "pyth0n3\n" .text .globl _start _start: movq $1, %rax movq $1, %rdi movq $NickName, %rsi movq $8, %rdx syscall movq $60, %rax movq $0, %rdi syscall Cum am mai spus exista mai multe variante pentru a scrie acest cod. Exemplu : Vom stampa "OK" pe ecran intrun mod divers sintaxa pentr 32 bit .text .globl _start _start: pushl $0x0a6b6f mov %esp, %ecx mov $0x4, %edx mov $0x4, %eax movl $1, %eax movl $0, %ebx int $0x80 Probabil exista greseli de exprimare, nu ezitati sa scrieti , le voi corecta. ###END
×
×
  • Create New...