Search the Community
Showing results for tags 'debug'.
-
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.
-
Acest tutorial este in legatura cu acest thread https://rstforums.com/forum/86916-run-time-error-13-type-mismatch.rst. L'am mutat aici fiind mai mult decat un simplu raspuns al thread-ului respectiv. Am explicat o posibila modalitate de rezolvare a erorilor de tip error-and-crash. Aplicatia exemplu este Youtube Viewer Am testat, la mine nu da eroare daca clipul are multe vizite (301+). Dar daca clipul are 20 de views atunci face o conexiune, face 1 view, si da Runtime Error 13: Type Mismatch Programul este foarte simplu, practic cu un socket face un requesturi spre YT folosind User agent Mozilla, cookiurile modificate ... si IPuri diferite fara a folosi proxy (?!). Type mismatch (13) apare, asa cum spunea @Ganav, atunci cand operanzii sunt incompatibili cu tipul operatiei. Un exemplu ar fi atunci cand o functie de conversie string-integer, care DEOBICEI intoarce un integer, nu poate converti valoarea de tip string. Astfel de 'bug'-uri apar frecvent in aplicatiile scrise de incepatori.. In cazul de fatza, ce se intampla concret nu e atat de important pe cat este rezolvarea problemei in sine. Aplicatia este practic un parser HTML. Face requestul, extrage valori din HTML pe care apoi le foloseste. Daca sursa site-ului se modifica, atunci evident extrage prost. Asta este motivul pentru care aplicatiile de tip crawler/parser dedicate trebuie actualizate mereu. Cred ca aplicatia vrea sa extraga numarul de views din pagina YT, dar scoate "50 views" in loc de "50", iar apoi crapa la conversia string-integer. Am explicat mai jos, pe cod. Am rulat atent si am observat ca eroarea apare imediat dupa ce apare notificarea in StatusBar: "Added view." Pornim OllyDBG, incarcam EXEul, debuger-ul ne duce pe EntryPoint, cautam dupa stringuri (clk dr, Search For-> All referenced text strings) si cautam "Added view". Il gasim la adresa 0041235F - undeva jos in lista. Dublu clk pe el si ajungem in cod exact acolo. ... ... 0041235F BA 10E64000 MOV EDX,40E610 ; UNICODE "Added view." 00412364 8D4D E8 LEA ECX,DWORD PTR SS:[EBP-18] 00412367 FF15 DC104000 CALL DWORD PTR DS:[4010DC] ; MSVBVM60.__vbaStrCopy 0041236D 8B16 MOV EDX,DWORD PTR DS:[ESI] 0041236F 8D45 BC LEA EAX,DWORD PTR SS:[EBP-44] 00412372 8D4D E8 LEA ECX,DWORD PTR SS:[EBP-18] 00412375 50 PUSH EAX 00412376 51 PUSH ECX 00412377 53 PUSH EBX 00412378 56 PUSH ESI ... ... Punem un brakepoint pe adresa 0041235F (F2), pentru ca debugerul sa opreasca aplicatia exact in locul ala, si rulam (F9). Aplicatia se incarca, apare formul, completam campul cu ID-ul video-ului care ne intereseaza, apasam pe START si asteptam eroarea. Debugerul ne opreste la adresa dorita (0041235F), chiar inainte sa primim eroarea. De aici putem rula Step-By-Step exact pana in locul unde va fi genereata eroarea. Ca sa economisim timp vom tine cont de ceea ce stim deja, si anume ca este o eroare tip Type Mismatch (13), care este generata de o functie MS; asadar cautam o functie de conversie din MSVBVM60.DLL Coboram (scrool) pana gasim: ... ... 00412496 8B95 4CFFFFFF MOV EDX,DWORD PTR SS:[EBP-B4] 0041249C 8B45 E8 MOV EAX,DWORD PTR SS:[EBP-18] 0041249F 50 PUSH EAX 004124A0 8B1A MOV EBX,DWORD PTR DS:[EDX] 004124A2 FF15 C8104000 CALL DWORD PTR DS:[4010C8] ; MSVBVM60.__vbaR8Str 004124A8 DC05 30114000 FADD QWORD PTR DS:[401130] 004124AE 83EC 08 SUB ESP,8 004124B1 DFE0 FSTSW AX 004124B3 A8 0D TEST AL,0D 004124B5 0F85 9E010000 JNZ 00412659 ; Youtubev.00412659 004124BB DD1C24 FSTP QWORD PTR SS:[ESP] 004124BE FF15 90104000 CALL DWORD PTR DS:[401090] ; MSVBVM60.__vbaStrR8 004124C4 8BD0 MOV EDX,EAX 004124C6 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-1C] 004124C9 FF15 10114000 CALL DWORD PTR DS:[401110] ; MSVBVM60.__vbaStrMove 004124CF 8BCB MOV ECX,EBX 004124D1 8B9D 4CFFFFFF MOV EBX,DWORD PTR SS:[EBP-B4] 004124D7 50 PUSH EAX 004124D8 53 PUSH EBX ... ... Observam la adresa 004124A2 : 004124A2 FF15 C8104000 CALL DWORD PTR DS:[4010C8] ; MSVBVM60.__vbaR8Str Este prima functie de conversie care ar putea genera eroarea. Pentru ca debugerul sa se opreasca pe ea punem breakpoint. (click pe 004124A2 , apoi F2) si rulam (F9). Ajungem exact acolo, cu ochii pe valorile din registri EAX, EBX, ECX, EDX (dreapta sus in debuger) Observam cum se incarca nr. de views in EAX ("50 views") iar apoi urmeaza executia functiei de conversie. Teoretic de aici vom putea rula mai departe Step-by-Step (F7) fiindca suntem foarte aproape, dar stim ca eroarea apartine programatorului, nu functiilor API MS, asa ca vom folosi Step Over (F8) ca sa nu intram prin aceasta functie. Apasam F8 (Step Over) si observam ca am sarit in total alta parte: observam in titlu module USER32, in ECX ASCII "ViewsTube", in ESI avem USER32.MesageBoxIndirectA. Rulam in continuare (F8) si mai observam "Type Mismatch", ... deci e clar: eroarea s'a produs DEJA iar programul se pregateste sa ne afiseze un MessageBox cu titlul "ViewsTube" si mesajul "Type Mismatch".. ------------ CONCLUZIA: unul dintre registrii este incarcat cu o valoare incompatibila cu tipurile cerute de __vbaR8Str. Umpic de research pe google aflam ca __vbaR8Str este o functie nedocumentata de Microsoft, dar daca ne mai uitam putin prin cod (...) aflam ca foloseste o alta functie VarR8FromStr, care transforma un string in double: : (source MSDN) VarR8FromStr function Converts an OLECHAR string to a double value. HRESULT VarR8FromStr( _In_ LPCOLESTR strIn, _In_ LCID lcid, _In_ ULONG dwFlags, _Out_ DOUBLE *pdblOut ); Deci cu siguranta aplicatia vrea sa transforme stringul "50 views" in integer, ceea ce, evident, nu este posibil. ------------------ SOLUTIA: In acest caz eroarea apare la afisarea numarului de views efectuati, nu in functionalitate. Isi face treaba, dar crapa cand vrea sa ne afiseze numarul actual de views. Exista doua variante: - reparam "zona cu probleme" - ocolim "zona cu probleme" Daca nu e ceva foarte important sa trebuiasca reparat, si mai ales daca facem asta din pasiune si nu pe bani, vom prefera intotdeauna sa ocolim, aplicatia fiind FUNCTIONALA (chiar daca nu va mai arata corect nr. de views...). A repara o astfel de eroare implica mai mult timp si cunostinte, cum ar fi programarea ASM si injectiile suplimentare de cod. Deci vom ocoli zona folosind doar o simpla intructiune JMP (jump). Cum facem asta? Avem trei variante: - patch direct in debuger - scriem un patcher.exe - scriem un loader.exe Oricare varianta este buna, cea mai rapida fiind prima, pe care o prefer: Deschidem aplicatia dinnou in debuger, reluam toti pasii, sau punem direct un breakpoint pe adresa functiei cu probleme (004124A2): 004124A2 FF15 C8104000 CALL DWORD PTR DS:[4010C8] ; MSVBVM60.__vbaR8Str Rulam (F9), pana ajungem acolo. Folosind JMP putem sari practic oriunde, dar e de preferat sa ocolim cat mai putin pentru a nu pierde sectiuni functionale din cod. Adreasa 004124A2 fiind selectata apasam SPACE (sau clk dr.-> Assemble) stergem tot ce este acolo si introducem instructiunea JMP alaturi de noua adresa: JMP 004124F7 Bifam "Fill with NOP's" Apasam "Assemble" apoi "Cancel" Modificarile apar marcate cu alb si o sageata verticala de la 004124A2 spre noua 004124F7. Rulam (F9) si observam ca programul face un view dupa care se opreste in brakepoint-ul setat; mai rulam odata, inca odata, inca odata, ... face treaba, fara erori! Perfect: acum SALVAM noul EXE: clk. dr pe cod -> Copy -> Select All apoi Copy to executable -> All modifications -> Copy All Salvam noul EXE cu nume diferit: clk dr. Save File: youtubeviewer_patched.exe -> Save Rulam noul EXE, zambim, am mai invatat ceva Patched File URL: https://www.sendspace.com/file/d4tit2
-
Are you tired of yet more externally exploitable buffer overflows in C programs? Do you want to audit your source for common mistakes? If so, PScan is for you! What PScan does: Scans C source files for problematic uses of printf style functions. e.g.: sprintf(buffer, variable); Bad! Possible security breach! sprintf(buffer, "%s", variable); Ok All of these security problems can also occur with any printf-style function. It is simple to fall into the trap of misusing printf and friends, thus, the need for PScan. What PScan does not do: - Scan for traditional buffer over-flows. - You should use a bounds-checking compiler for that. - Scan for any other mis-use of function parameters. The functionality given by PScan is limited. Yet it may be useful. I'm not going to claim it's the be-all and end-all of security scanners, but it does one thing, and it does it simply, and reasonably well. Newer versions of GCC do a better job of scanning source files for problems, but they require the code to be compiled. Pscan is a lot faster, but not as good. As always, there are trade-offs in life. Analyzing and correcting the security breaches is up to the programmer. Let's run PScan over an old version of wu-ftpd. The text below is a sample of the output from PScan: [aland@www pscan]$ ./pscan -p wu-ftpd.pscan ../wu-ftpd-2.6.1/src/*.c ../wu-ftpd-2.6.1/src/ftpd.c:2575 FUNC reply ../wu-ftpd-2.6.1/src/ftpd.c:6277 FUNC syslog ../wu-ftpd-2.6.1/src/ftpd.c:6292 FUNC syslog ../wu-ftpd-2.6.1/src/ftpd.c:6438 FUNC reply [aland@www pscan]$ From the area around line 6277 of ftpd.c, with the problem line emphasized, the code is 6271: if (debug) { 6273: char *s = calloc(128 + strlen(remoteident), sizeof(char)); 6274: if (s) { 6275: int i = ntohs(pasv_addr.sin_port); 6276: sprintf(s, "PASV port %i assigned to %s", i, remoteident); 6277: syslog(LOG_DEBUG, s); 6278: free(s); 6279: } 6280: } So we can see that if the variable debug is set, and the variable remoteident can be set externally (say by an anonymous FTP user), then there may be an exploitable hole in the call to syslog. If we root around the source a little more, we discover in ftpd.c: 6037: else if (authenticated) 6038: sprintf(remoteident, "%s @ %s [%s]", 6039: authuser, remotehost, remoteaddr); 6040: else 6041: sprintf(remoteident, "%s [%s]", remotehost, remoteaddr); The remotehost variable holds the host name of the remote host which is currently connected. A malicious user may set the DNS hostname to a string which contains carefully constructed formatting codes recognized by the sprintf and syslog functions. This problem may allow him to cause the ftp daemon to core dump, or even for him to gain access to a root shell. The solution is to correct line 6277 in the source. The suggested replacement line is below, with the changes emphasized 6277: syslog(LOG_DEBUG, "%s", s); Trusting user input is a bad thing for any program to do. Download: http://deployingradius.com/pscan/pscan.tar.gz Source: PScan: A limited problem scanner for C source files
-
- 1
-
- c source files
- debug
-
(and 3 more)
Tagged with: