=============== level7 tutorial =============== Let's run gdb first. $ gdb /home/labs/week1/level7/level7 pwndbg> disass main Dump of assembler code for function main: 0x080488d0 <+0>: push %ebp 0x080488d1 <+1>: mov %esp,%ebp 0x080488d3 <+3>: sub $0x8,%esp 0x080488d6 <+6>: lea 0x8048a14,%eax 0x080488dc <+12>: mov %eax,(%esp) 0x080488df <+15>: call 0x8048430 0x080488e4 <+20>: mov %eax,-0x4(%ebp) 0x080488e7 <+23>: call 0x80486c0 0x080488ec <+28>: xor %eax,%eax 0x080488ee <+30>: add $0x8,%esp 0x080488f1 <+33>: pop %ebp 0x080488f2 <+34>: ret End of assembler dump. The main() function runs: printf(0x8048a14); password(); Let's move on to password(): pwndbg> disass password Dump of assembler code for function password: 0x080486c0 <+0>: push %ebp 0x080486c1 <+1>: mov %esp,%ebp 0x080486c3 <+3>: push %ebx 0x080486c4 <+4>: push %edi 0x080486c5 <+5>: push %esi 0x080486c6 <+6>: sub $0x25c,%esp 0x080486cc <+12>: lea 0x80489a7,%eax 0x080486d2 <+18>: lea -0x20c(%ebp),%ecx 0x080486d8 <+24>: xor %edx,%edx 0x080486da <+26>: mov $0x200,%esi 0x080486df <+31>: mov %ecx,(%esp) 0x080486e2 <+34>: movl $0x0,0x4(%esp) 0x080486ea <+42>: movl $0x200,0x8(%esp) 0x080486f2 <+50>: mov %eax,-0x218(%ebp) 0x080486f8 <+56>: mov %ecx,-0x21c(%ebp) 0x080486fe <+62>: mov %edx,-0x220(%ebp) 0x08048704 <+68>: mov %esi,-0x224(%ebp) 0x0804870a <+74>: call 0x8048470 0x0804870f <+79>: mov -0x218(%ebp),%eax 0x08048715 <+85>: mov %eax,(%esp) 0x08048718 <+88>: mov -0x21c(%ebp),%ecx 0x0804871e <+94>: mov %ecx,0x4(%esp) 0x08048722 <+98>: call 0x80484c0 <__isoc99_scanf@plt> 0x08048727 <+103>: lea 0x80489ac,%ecx 0x0804872d <+109>: lea -0x20c(%ebp),%edx 0x08048733 <+115>: mov %ecx,(%esp) 0x08048736 <+118>: mov %edx,0x4(%esp) 0x0804873a <+122>: mov %eax,-0x228(%ebp) 0x08048740 <+128>: call 0x8048430 0x08048745 <+133>: lea -0x20c(%ebp),%ecx 0x0804874b <+139>: mov %esp,%edx 0x0804874d <+141>: mov %ecx,(%edx) 0x0804874f <+143>: mov %eax,-0x22c(%ebp) 0x08048755 <+149>: mov %ecx,-0x230(%ebp) 0x0804875b <+155>: call 0x8048450 0x08048760 <+160>: mov %eax,-0x210(%ebp) 0x08048766 <+166>: mov -0x210(%ebp),%eax 0x0804876c <+172>: mov -0x230(%ebp),%ecx 0x08048772 <+178>: mov %ecx,(%esp) 0x08048775 <+181>: mov %eax,0x4(%esp) 0x08048779 <+185>: call 0x80484a0 0x0804877e <+190>: lea -0x20c(%ebp),%ecx 0x08048784 <+196>: mov %ecx,(%esp) 0x08048787 <+199>: mov %eax,-0x234(%ebp) 0x0804878d <+205>: call 0x8048660 0x08048792 <+210>: lea -0x20c(%ebp),%eax 0x08048798 <+216>: mov %eax,(%esp) 0x0804879b <+219>: call 0x80484d0 0x080487a0 <+224>: lea 0x80489bd,%ecx 0x080487a6 <+230>: mov %eax,-0x214(%ebp) 0x080487ac <+236>: mov -0x214(%ebp),%eax 0x080487b2 <+242>: mov %ecx,(%esp) 0x080487b5 <+245>: mov %eax,0x4(%esp) 0x080487b9 <+249>: call 0x8048430 0x080487be <+254>: mov $0x14,%ecx 0x080487c3 <+259>: lea 0x80489cf,%edx 0x080487c9 <+265>: lea -0x20c(%ebp),%esi 0x080487cf <+271>: mov -0x214(%ebp),%edi 0x080487d5 <+277>: mov %esi,(%esp) 0x080487d8 <+280>: movl $0x14,0x4(%esp) 0x080487e0 <+288>: mov %edx,0x8(%esp) 0x080487e4 <+292>: mov %edi,0xc(%esp) 0x080487e8 <+296>: mov %eax,-0x238(%ebp) 0x080487ee <+302>: mov %ecx,-0x23c(%ebp) 0x080487f4 <+308>: call 0x8048480 0x080487f9 <+313>: lea 0x80489d2,%ecx 0x080487ff <+319>: lea -0x20c(%ebp),%edx 0x08048805 <+325>: mov %ecx,(%esp) 0x08048808 <+328>: mov %edx,0x4(%esp) 0x0804880c <+332>: mov %eax,-0x240(%ebp) 0x08048812 <+338>: call 0x8048430 0x08048817 <+343>: lea -0x20c(%ebp),%ecx 0x0804881d <+349>: mov %esp,%edx 0x0804881f <+351>: mov %ecx,(%edx) 0x08048821 <+353>: mov %eax,-0x244(%ebp) 0x08048827 <+359>: mov %ecx,-0x248(%ebp) 0x0804882d <+365>: call 0x8048450 0x08048832 <+370>: mov %eax,-0x210(%ebp) 0x08048838 <+376>: mov -0x210(%ebp),%eax 0x0804883e <+382>: mov -0x248(%ebp),%ecx 0x08048844 <+388>: mov %ecx,(%esp) 0x08048847 <+391>: mov %eax,0x4(%esp) 0x0804884b <+395>: call 0x80484a0 0x08048850 <+400>: lea -0x20c(%ebp),%ecx 0x08048856 <+406>: mov %ecx,(%esp) 0x08048859 <+409>: mov %eax,-0x24c(%ebp) 0x0804885f <+415>: call 0x8048660 0x08048864 <+420>: lea -0x20c(%ebp),%eax 0x0804886a <+426>: mov (%eax),%eax 0x0804886c <+428>: sub $0x68333a3e,%eax 0x08048871 <+433>: setne %bl 0x08048874 <+436>: movzbl %bl,%ecx 0x08048877 <+439>: cmp $0x0,%ecx 0x0804887a <+442>: mov %eax,-0x250(%ebp) 0x08048880 <+448>: jne 0x80488a4 0x08048886 <+454>: lea 0x80489f0,%eax 0x0804888c <+460>: mov %eax,(%esp) 0x0804888f <+463>: call 0x8048430 0x08048894 <+468>: mov %eax,-0x254(%ebp) 0x0804889a <+474>: call 0x80485f0 0x0804889f <+479>: jmp 0x80488b8 0x080488a4 <+484>: lea 0x8048a0d,%eax 0x080488aa <+490>: mov %eax,(%esp) 0x080488ad <+493>: call 0x8048430 0x080488b2 <+498>: mov %eax,-0x258(%ebp) 0x080488b8 <+504>: add $0x25c,%esp 0x080488be <+510>: pop %esi 0x080488bf <+511>: pop %edi 0x080488c0 <+512>: pop %ebx 0x080488c1 <+513>: pop %ebp 0x080488c2 <+514>: ret Let's analyze the first call: Dump of assembler code for function password: 0x080486c0 <+0>: push %ebp 0x080486c1 <+1>: mov %esp,%ebp 0x080486c3 <+3>: push %ebx 0x080486c4 <+4>: push %edi 0x080486c5 <+5>: push %esi 0x080486c6 <+6>: sub $0x25c,%esp 0x080486cc <+12>: lea 0x80489a7,%eax 0x080486d2 <+18>: lea -0x20c(%ebp),%ecx <-- ecx, 1st arg... 0x080486d8 <+24>: xor %edx,%edx 0x080486da <+26>: mov $0x200,%esi 0x080486df <+31>: mov %ecx,(%esp) <-- 1st arg (ebp_20c) 0x080486e2 <+34>: movl $0x0,0x4(%esp) <-- 2nd arg (0) 0x080486ea <+42>: movl $0x200,0x8(%esp) <-- 3rd arg (0x200) 0x080486f2 <+50>: mov %eax,-0x218(%ebp) 0x080486f8 <+56>: mov %ecx,-0x21c(%ebp) 0x080486fe <+62>: mov %edx,-0x220(%ebp) 0x08048704 <+68>: mov %esi,-0x224(%ebp) 0x0804870a <+74>: call 0x8048470 These snippets are: char buffer[0x200]; // ebp_20c memset(buffer, 0, 0x200); Let's move on to the next: 0x0804870f <+79>: mov -0x218(%ebp),%eax 0x08048715 <+85>: mov %eax,(%esp) <-- 1st arg (ebp_218) 0x08048718 <+88>: mov -0x21c(%ebp),%ecx <-- this is mov, so we need to analyze lea. 0x0804871e <+94>: mov %ecx,0x4(%esp) <-- 2nd arg (ebp_21c) 0x08048722 <+98>: call 0x80484c0 <__isoc99_scanf@plt> scanf(ebp_218, ebp_21c); Because we usually use scanf like: int i; scanf("%d", &i); So the first argument should be a format string, and the 2nd argument is an address to a variable. Let's figure out the 1st argument first, which comes from ebp_218. By taking a look at some lines up there, 0x080486cc <+12>: lea 0x80489a7,%eax <-- eax comes from 0x80489a7 0x080486d2 <+18>: lea -0x20c(%ebp),%ecx 0x080486d8 <+24>: xor %edx,%edx 0x080486da <+26>: mov $0x200,%esi 0x080486df <+31>: mov %ecx,(%esp) 0x080486e2 <+34>: movl $0x0,0x4(%esp) 0x080486ea <+42>: movl $0x200,0x8(%esp) 0x080486f2 <+50>: mov %eax,-0x218(%ebp) <-- ebp_218 = eax; eax = 0x80489a7, and the address 0x80489a7 contains: pwndbg> x/s 0x80489a7 0x80489a7: "%50s" Yes, it is: int i; // ebp_21c scanf(0x80489a7, &i); Oh, it's a string, max length as 50. Then let's change it as: char input_buffer[50]; // ebp_21c scanf("%50s", input_buffer); But let's check the 2nd argument because: 0x08048718 <+88>: mov -0x21c(%ebp),%ecx <-- this is mov, so we need to analyze lea. 0x0804871e <+94>: mov %ecx,0x4(%esp) <-- 2nd arg (ebp_21c) What we expect for the 2nd argument of scanf() is an address, but none of these two uses 'lea', the instruction which stores an 'address'. Then, let's collect all instructions related to ebp_21c; 0x080486d2 <+18>: lea -0x20c(%ebp),%ecx <-- ecx = address of ebp_20c; 0x080486d8 <+24>: xor %edx,%edx 0x080486da <+26>: mov $0x200,%esi 0x080486df <+31>: mov %ecx,(%esp) 0x080486e2 <+34>: movl $0x0,0x4(%esp) 0x080486ea <+42>: movl $0x200,0x8(%esp) 0x080486f2 <+50>: mov %eax,-0x218(%ebp) 0x080486f8 <+56>: mov %ecx,-0x21c(%ebp) <-- ebp_21c = ecx Yes, ebp_21c stores the address of ebp_20c, and it's 'buffer' with which the program runs memset at the start.. So we may rewrite code up to this point as: char buffer[0x200]; // ebp_20c memset(buffer, 0, 0x200); scanf("%50s", buffer); Next is printf. 0x08048727 <+103>: lea 0x80489ac,%ecx <-- ecx = 0x80489ac 0x0804872d <+109>: lea -0x20c(%ebp),%edx 0x08048733 <+115>: mov %ecx,(%esp) <-- 1st arg (0x80489ac) 0x08048736 <+118>: mov %edx,0x4(%esp) <-- 2nd arg, (&ebp_20c, buffer) 0x0804873a <+122>: mov %eax,-0x228(%ebp) 0x08048740 <+128>: call 0x8048430 It's printf(0x80489ac, buffer); pwndbg> x/s 0x80489ac 0x80489ac: "Your buffer: %s\n" So it's: printf("Your buffer: %s\n", buffer); Just printing out our input. Next, 0x08048745 <+133>: lea -0x20c(%ebp),%ecx 0x0804874b <+139>: mov %esp,%edx <-- now edx is esp. 0x0804874d <+141>: mov %ecx,(%edx) <-- 1st arg, &ebp_20c, buffer! 0x0804874f <+143>: mov %eax,-0x22c(%ebp) 0x08048755 <+149>: mov %ecx,-0x230(%ebp) 0x0804875b <+155>: call 0x8048450 it calls: size_t length = strlen(buffer); Because it returns the length in eax, we need to focus on how eax will be used in following instructions: 0x08048760 <+160>: mov %eax,-0x210(%ebp) <-- ebp_210 = length; 0x08048766 <+166>: mov -0x210(%ebp),%eax <-- eax = length; 0x0804876c <+172>: mov -0x230(%ebp),%ecx <-- ecx = ebp_230 0x08048772 <+178>: mov %ecx,(%esp) <-- 1st arg 0x08048775 <+181>: mov %eax,0x4(%esp) <-- 2nd arg, length 0x08048779 <+185>: call 0x80484a0 So it calls memfrob(ebp_230, length); Let's check the signature of memfrob: void *memfrob(void *s, size_t n); So we expect the 1st argument as an address. Let's check how ebp_230 was accessed before: 0x08048745 <+133>: lea -0x20c(%ebp),%ecx <-- ecx = &ebp_20c = buffer; 0x0804874b <+139>: mov %esp,%edx 0x0804874d <+141>: mov %ecx,(%edx) 0x0804874f <+143>: mov %eax,-0x22c(%ebp) 0x08048755 <+149>: mov %ecx,-0x230(%ebp) <-- ebp_230 = buffer! It's buffer. So it calls: memfrob(buffer, length); And then, it calls add_a_space(): 0x0804877e <+190>: lea -0x20c(%ebp),%ecx <-- ecx = &ebp_20c = buffer 0x08048784 <+196>: mov %ecx,(%esp) <-- 1st arg (buffer) 0x08048787 <+199>: mov %eax,-0x234(%ebp) 0x0804878d <+205>: call 0x8048660 add_a_space(buffer); Because add_a_space is not attached with a suffix @plt, it's a function in the program. Let's take a look at that function: 0x08048660 <+0>: push %ebp 0x08048661 <+1>: mov %esp,%ebp 0x08048663 <+3>: sub $0x8,%esp 0x08048666 <+6>: mov 0x8(%ebp),%eax <-- this line fetches function argument, eax = buffer; Because this function has an argument (buffer), the function accesses the argument by applying positive indexing on ebp. Here, 0x8(%ebp) is the 1st argument of the function. Because stack grows downward, you may access 2nd, 3rd, 4th, .. arguments by applying +4 on the index. E.g., 0xc(%ebp) stores the 2nd argument 0x10(%ebp) stores the 3rd argument 0x14(%ebp) stores the 4th argument, and so on... 0x08048669 <+9>: mov %eax,-0x4(%ebp) <-- so this line is, ebp_4 = buffer; 0x0804866c <+12>: movl $0x0,-0x8(%ebp) 0x08048673 <+19>: mov -0x8(%ebp),%eax 0x08048676 <+22>: mov -0x4(%ebp),%ecx 0x08048679 <+25>: movsbl (%ecx,%eax,1),%eax 0x0804867d <+29>: cmp $0x0,%eax 0x08048680 <+32>: je 0x80486b1 We have cmp/je combo here.. it jumps to +81, and 0x08048686 <+38>: mov -0x8(%ebp),%eax 0x08048689 <+41>: mov -0x4(%ebp),%ecx 0x0804868c <+44>: movsbl (%ecx,%eax,1),%eax 0x08048690 <+48>: add $0x20,%eax 0x08048693 <+51>: and $0xff,%eax 0x08048698 <+56>: mov %al,%dl 0x0804869a <+58>: mov -0x8(%ebp),%eax 0x0804869d <+61>: mov -0x4(%ebp),%ecx 0x080486a0 <+64>: mov %dl,(%ecx,%eax,1) 0x080486a3 <+67>: mov -0x8(%ebp),%eax 0x080486a6 <+70>: add $0x1,%eax 0x080486a9 <+73>: mov %eax,-0x8(%ebp) 0x080486ac <+76>: jmp 0x8048673 Right before +81, we have jump back to +19. Then, we may regard this as a loop between +19 and +76. So it's a loop, and: 0x0804866c <+12>: movl $0x0,-0x8(%ebp) <-- loop variable as 0. 0x08048673 <+19>: mov -0x8(%ebp),%eax <-- eax stores loop varible. Let's set it as i; 0x08048676 <+22>: mov -0x4(%ebp),%ecx <-- ebp_4 stores buffer, so ecx = buffer; 0x08048679 <+25>: movsbl (%ecx,%eax,1),%eax This line is: eax = ecx[eax * 1]; -> eax = buffer[eax * 1]; -> eax = buffer[i]; 0x0804867d <+29>: cmp $0x0,%eax And it compares it to value 0, and 0x08048680 <+32>: je 0x80486b1 jump out the loop if it is matched (je means 'jump if equal'); And to get the loop increment statement, you may check the end of the loop: 0x080486a3 <+67>: mov -0x8(%ebp),%eax <-- loop variable increment 0x080486a6 <+70>: add $0x1,%eax 0x080486a9 <+73>: mov %eax,-0x8(%ebp) ebp_8 += 1; In this case, we can write this as: for (int i=0; buffer[i] != 0; ++i) { 0x08048686 <+38>: mov -0x8(%ebp),%eax // eax = ebp_8 = i; 0x08048689 <+41>: mov -0x4(%ebp),%ecx // ecx = ebp_4 = buffer; 0x0804868c <+44>: movsbl (%ecx,%eax,1),%eax // eax = buffer[i]; 0x08048690 <+48>: add $0x20,%eax // eax += 0x20; 0x08048693 <+51>: and $0xff,%eax // eax &= 0xff; 0x08048698 <+56>: mov %al,%dl // dl = the last 1 byte of eax; 0x0804869a <+58>: mov -0x8(%ebp),%eax // eax = ebp_8 = i; 0x0804869d <+61>: mov -0x4(%ebp),%ecx // ecx = ebp_4 = buffer; 0x080486a0 <+64>: mov %dl,(%ecx,%eax,1) the instruction runs: (0 + ecx)[eax] = dl; and it is: buffer[i] = dl; So what it does is: char c = buffer[i]; c += 0x20; c &= 0xff; buffer[i] = c; } In summary, add_a_space does: void add_a_space(char *buffer) { for (int i=0; buffer[i] != 0; ++i) { buffer[i] += 0x20; } } Yes, it adds the value 0x20 to the buffer. And to give a hint about what this function does, 'A' is 0x41, and 'a' is 0x61 in ASCII code. Likewise, 'B' is 0x42, and 'b' is 0x62. So adding 0x20 will change an uppercase character to a lowercase character (and just change the value if original character is not an uppercase character). And, let's summarize password() here again: void password() { char buffer[0x200]; // ebp_20c memset(buffer, 0, 0x200); scanf("%50s", buffer); printf("Your buffer: %s\n", buffer); size_t length = strlen(buffer); memfrob(buffer, length); add_a_space(buffer); ... } Let's move on to next: 0x08048792 <+210>: lea -0x20c(%ebp),%eax 0x08048798 <+216>: mov %eax,(%esp) <-- 1st arg, ebp_20c, buffer 0x0804879b <+219>: call 0x80484d0 It runs: result_of_atoi = eax = atoi(buffer); 0x080487a0 <+224>: lea 0x80489bd,%ecx <-- ecx is from here 0x080487a6 <+230>: mov %eax,-0x214(%ebp) <-- ebp_214 stores value returned by atoi 0x080487ac <+236>: mov -0x214(%ebp),%eax 0x080487b2 <+242>: mov %ecx,(%esp) <-- 1st arg, 0x80489bd 0x080487b5 <+245>: mov %eax,0x4(%esp) <-- 2nd arg, 0x080487b9 <+249>: call 0x8048430 and it runs: printf(0x80489bd, result_of_atoi) -> printf("Your Integer: %u\n", result_of_atoi) 0x080487be <+254>: mov $0x14,%ecx 0x080487c3 <+259>: lea 0x80489cf,%edx <-- edx 0x080487c9 <+265>: lea -0x20c(%ebp),%esi <-- esi = &ebp_20c, buffer 0x080487cf <+271>: mov -0x214(%ebp),%edi 0x080487d5 <+277>: mov %esi,(%esp) <-- 1st arg (buffer) 0x080487d8 <+280>: movl $0x14,0x4(%esp) <-- 2nd arg (0x14, 20) 0x080487e0 <+288>: mov %edx,0x8(%esp) <-- 3rd arg, edx, 0x80489cf 0x080487e4 <+292>: mov %edi,0xc(%esp) <-- 4th arg, edi, ebp_214, result of atoi. 0x080487e8 <+296>: mov %eax,-0x238(%ebp) 0x080487ee <+302>: mov %ecx,-0x23c(%ebp) 0x080487f4 <+308>: call 0x8048480 and then it runs snprintf: snprintf(buffer, 0x14, 0x80489cf, result_of_atoi); -> snprintf(buffer, 0x14, "%x", result_of_atoi); 0x080487f9 <+313>: lea 0x80489d2,%ecx 0x080487ff <+319>: lea -0x20c(%ebp),%edx 0x08048805 <+325>: mov %ecx,(%esp) <-- 1st arg, 0x80489d2 0x08048808 <+328>: mov %edx,0x4(%esp) <-- 2nd, buffer 0x0804880c <+332>: mov %eax,-0x240(%ebp) 0x08048812 <+338>: call 0x8048430 and then it prints out: printf("Your Hex Integer: %s\n", buffer); 0x08048817 <+343>: lea -0x20c(%ebp),%ecx 0x0804881d <+349>: mov %esp,%edx <-- edx = esp 0x0804881f <+351>: mov %ecx,(%edx) <-- 1st arg, buffer 0x08048821 <+353>: mov %eax,-0x244(%ebp) 0x08048827 <+359>: mov %ecx,-0x248(%ebp) 0x0804882d <+365>: call 0x8048450 and then it calls: size_t buffer_string_length = strlen(buffer); 0x08048832 <+370>: mov %eax,-0x210(%ebp) <-- buffer length is at ebp_210 0x08048838 <+376>: mov -0x210(%ebp),%eax <-- get that back to eax 0x0804883e <+382>: mov -0x248(%ebp),%ecx 0x08048844 <+388>: mov %ecx,(%esp) <-- ebp_248, and +359 and +343 says it is &ebp_20c, buffer. 0x08048847 <+391>: mov %eax,0x4(%esp) <-- buffer_string_length 0x0804884b <+395>: call 0x80484a0 and then: memfrob(buffer, buffer_string_length) 0x08048850 <+400>: lea -0x20c(%ebp),%ecx <-- ecx = buffer 0x08048856 <+406>: mov %ecx,(%esp) <-- 1st arg, buffer 0x08048859 <+409>: mov %eax,-0x24c(%ebp) 0x0804885f <+415>: call 0x8048660 and then apply add_a_space again: add_a_space(buffer); Let's summarize the decompiled code up to this point: void password() { char buffer[0x200]; // ebp_20c memset(buffer, 0, 0x200); scanf("%50s", buffer); printf("Your buffer: %s\n", buffer); size_t length = strlen(buffer); memfrob(buffer, length); add_a_space(buffer); result_of_atoi = atoi(buffer); printf("Your Integer: %u\n", result_of_atoi) snprintf(buffer, 0x14, "%x", result_of_atoi); printf("Your Hex Integer: %s\n", buffer); size_t buffer_string_length = strlen(buffer); memfrob(buffer, buffer_string_length) add_a_space(buffer); ... } Let's analyze the final steps.. 0x08048864 <+420>: lea -0x20c(%ebp),%eax <-- eax = buffer; 0x0804886a <+426>: mov (%eax),%eax <-- eax = *((int*)buffer); get the 1st 4 byte from buffer... 0x0804886c <+428>: sub $0x68333a3e,%eax <-- eax -= 0x68333a3e 0x08048871 <+433>: setne %bl // this will make bl = 1 if eax != 0 (set 1 if not equal..) 0x08048874 <+436>: movzbl %bl,%ecx // ecx will store that value and.. 0x08048877 <+439>: cmp $0x0,%ecx // ecx == 0 if eax == 0x68333a3e, ecx == 1 if eax != 0x68333a3e 0x0804887a <+442>: mov %eax,-0x250(%ebp) 0x08048880 <+448>: jne 0x80488a4 // jump to 484 if ecx == 1, which is eax != 0x68333a3e.. So it checks for: int value = *((int*) buffer); if (value == 0x68333a3e) { 0x08048886 <+454>: lea 0x80489f0,%eax 0x0804888c <+460>: mov %eax,(%esp) <-- 1st arg, 0x80489f0 0x0804888f <+463>: call 0x8048430 pwndbg> x/s 0x80489f0 0x80489f0: "Great! you got my password!\n" printf("Great! you got my password!\n"); 0x08048894 <+468>: mov %eax,-0x254(%ebp) 0x0804889a <+474>: call 0x80485f0 0x0804889f <+479>: jmp 0x80488b8 get_a_shell(); } else { 0x080488a4 <+484>: lea 0x8048a0d,%eax 0x080488aa <+490>: mov %eax,(%esp) <-- 1st arg, 0x8048a0d 0x080488ad <+493>: call 0x8048430 0x080488b2 <+498>: mov %eax,-0x258(%ebp) pwndbg> x/s 0x8048a0d 0x8048a0d: "Oh no\n" printf("Oh no\n") } 0x080488b8 <+504>: add $0x25c,%esp 0x080488be <+510>: pop %esi 0x080488bf <+511>: pop %edi 0x080488c0 <+512>: pop %ebx 0x080488c1 <+513>: pop %ebp 0x080488c2 <+514>: ret and END... The decompiled code looks like: void password() { char buffer[0x200]; // ebp_20c memset(buffer, 0, 0x200); scanf("%50s", buffer); printf("Your buffer: %s\n", buffer); size_t length = strlen(buffer); memfrob(buffer, length); add_a_space(buffer); result_of_atoi = atoi(buffer); printf("Your Integer: %u\n", result_of_atoi) snprintf(buffer, 0x14, "%x", result_of_atoi); printf("Your Hex Integer: %s\n", buffer); size_t buffer_string_length = strlen(buffer); memfrob(buffer, buffer_string_length) add_a_space(buffer); int value = *((int*) buffer); if (value == 0x68333a3e) { printf("Great! you got my password!\n"); get_a_shell(); } else { printf("Oh no\n") } } ___ ___ __ _ | \/ | / _| | | | . . | ___ _ __ ___ | |_ _ __ ___ | |__ | |\/| |/ _ \ '_ ` _ \| _| '__/ _ \| '_ \ | | | | __/ | | | | | | | | | (_) | |_) | \_| |_/\___|_| |_| |_|_| |_| \___/|_.__/ ___ _ _ / _ \ | | | | / /_\ \ __| | __| | __ _ ___ _ __ __ _ ___ ___ | _ |/ _` |/ _` | / _` | / __| '_ \ / _` |/ __/ _ \ | | | | (_| | (_| | | (_| | \__ \ |_) | (_| | (_| __/ \_| |_/\__,_|\__,_| \__,_| |___/ .__/ \__,_|\___\___| | | |_| _ _ __ (_) | | / _| ___ _ __ _ __ _ __ _ _ __ | |_| |_ / __| '_ \| '_ \| '__| | '_ \| __| _| \__ \ | | | |_) | | | | | | | |_| | |___/_| |_| .__/|_| |_|_| |_|\__|_| | | |_| _ _ _ _ _ _ _ | (_) | | | | | | (_) | |_| |_| |_| | ___ ___ _ __ __| |_ __ _ _ __ | | | __| __| |/ _ \ / _ \ '_ \ / _` | |/ _` | '_ \ | | | |_| |_| | __/ | __/ | | | (_| | | (_| | | | | |_|_|\__|\__|_|\___| \___|_| |_|\__,_|_|\__,_|_| |_| _ _ _ _ | | | | | | | __ _ ___| |_ __ _ ___| |__ ___| | | / _` |/ _ \ __| / _` | / __| '_ \ / _ \ | | | (_| | __/ |_ | (_| | \__ \ | | | __/ | | \__, |\___|\__| \__,_| |___/_| |_|\___|_|_| __/ | |___/