After a slight hiatus from the topic of reverse engineering, and computer science as a whole (more tended towards focusing on pure mathematics and my own education), I return with this crackme, it is one made in C++ and I don’t really want to use a decompiler since that’s for skids (ref. to fundamental theorem of skid psychology here).
0x0000000008001195 <+0>: push %rbp
0x0000000008001196 <+1>: mov %rsp,%rbp
0x0000000008001199 <+4>: sub $0x10,%rsp
0x000000000800119d <+8>: lea 0xe61(%rip),%rsi # 0x8002005
0x00000000080011a4 <+15>: lea 0x2fd5(%rip),%rdi # 0x8004180 <_ZSt4cout@@GLIBCXX_3.4>
0x00000000080011ab <+22>: callq 0x8001050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x00000000080011b0 <+27>: mov %rax,%rdx
0x00000000080011b3 <+30>: mov 0x2e16(%rip),%rax # 0x8003fd0
0x00000000080011ba <+37>: mov %rax,%rsi
0x00000000080011bd <+40>: mov %rdx,%rdi
0x00000000080011c0 <+43>: callq 0x8001060 <_ZNSolsEPFRSoS_E@plt>
0x00000000080011c5 <+48>: callq 0x8001329 <_Z8get_codev>
0x00000000080011ca <+53>: mov %rax,-0x10(%rbp)
0x00000000080011ce <+57>: lea 0x31eb(%rip),%rdi # 0x80043c0 <code>
0x00000000080011d5 <+64>: callq 0x8001265 <_Z10check_codePi>
0x00000000080011da <+69>: xor $0x1,%eax
0x00000000080011dd <+72>: test %al,%al
0x00000000080011df <+74>: je 0x80011fe <main+105>
0x00000000080011e1 <+76>: lea 0xe38(%rip),%rsi # 0x8002020
0x00000000080011e8 <+83>: lea 0x2f91(%rip),%rdi # 0x8004180 <_ZSt4cout@@GLIBCXX_3.4>
0x00000000080011ef <+90>: callq 0x8001050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x00000000080011f4 <+95>: mov $0x0,%edi
0x00000000080011f9 <+100>: callq 0x8001070 <exit@plt>
0x00000000080011fe <+105>: lea 0xe23(%rip),%rsi # 0x8002028
0x0000000008001205 <+112>: lea 0x2f74(%rip),%rdi # 0x8004180 <_ZSt4cout@@GLIBCXX_3.4>
0x000000000800120c <+119>: callq 0x8001050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x0000000008001211 <+124>: movl $0x0,-0x4(%rbp)
0x0000000008001218 <+131>: cmpl $0x3,-0x4(%rbp)
0x000000000800121c <+135>: jg 0x8001248 <main+179>
0x000000000800121e <+137>: mov -0x4(%rbp),%eax
0x0000000008001221 <+140>: cltq
0x0000000008001223 <+142>: lea 0x0(,%rax,4),%rdx
0x000000000800122b <+150>: mov -0x10(%rbp),%rax
0x000000000800122f <+154>: add %rdx,%rax
0x0000000008001232 <+157>: mov (%rax),%eax
0x0000000008001234 <+159>: mov %eax,%esi
0x0000000008001236 <+161>: lea 0x2f43(%rip),%rdi # 0x8004180 <_ZSt4cout@@GLIBCXX_3.4>
0x000000000800123d <+168>: callq 0x8001090 <_ZNSolsEi@plt>
0x0000000008001242 <+173>: addl $0x1,-0x4(%rbp)
0x0000000008001246 <+177>: jmp 0x8001218 <main+131>
0x0000000008001248 <+179>: mov 0x2d81(%rip),%rax # 0x8003fd0
0x000000000800124f <+186>: mov %rax,%rsi
0x0000000008001252 <+189>: lea 0x2f27(%rip),%rdi # 0x8004180 <_ZSt4cout@@GLIBCXX_3.4>
0x0000000008001259 <+196>: callq 0x8001060 <_ZNSolsEPFRSoS_E@plt>
0x000000000800125e <+201>: mov $0x0,%eax
0x0000000008001263 <+206>: leaveq
0x0000000008001264 <+207>: retq
Now since I’m dealing with C++ the names are mangled for reasons of space optimization and probably some other obscure reasons, but one can unmask these mangled names by using c++filt
, and so I shall do so:
[1]_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
=> std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
_ZNSolsEPFRSoS_E
=> std::ostream::operator<<(std::ostream& (*)(std::ostream&))
_Z8get_codev
=> get_code()
_Z10check_codePi
=> check_code(int*)
_ZSt4cout
=> std::cout
_ZNSolsEi
=> std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
[1] i assume this is for calling the `<<` operator over some given `std::basic_stream` with a C-string for the second parameter, also allowing for chaining as i learned as the return value is another stream so you can chain together `<<` operations instead of having them be individual
So, let’s start somewhere:
0x0000000008001195 <+0>: push %rbp
0x0000000008001196 <+1>: mov %rsp,%rbp
0x0000000008001199 <+4>: sub $0x10,%rsp
0x000000000800119d <+8>: lea 0xe61(%rip),%rsi # 0x8002005
0x00000000080011a4 <+15>: lea 0x2fd5(%rip),%rdi # 0x8004180 <_ZSt4cout@@GLIBCXX_3.4>
0x00000000080011ab <+22>: callq 0x8001050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x00000000080011b0 <+27>: mov %rax,%rdx
0x00000000080011b3 <+30>: mov 0x2e16(%rip),%rax # 0x8003fd0 [2]
0x00000000080011ba <+37>: mov %rax,%rsi
0x00000000080011bd <+40>: mov %rdx,%rdi
0x00000000080011c0 <+43>: callq 0x8001060 <std::ostream::operator<<(std::ostream& (*)(std::ostream&))@plt>
0x00000000080011c5 <+48>: callq 0x8001329 <_Z8get_codev>
[2] 0x8003fd0 is a pointer to a `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)`
Equivalent to:
int
main ()
{
std::cout << "Please Enter The Passcode:" << std::endl;
get_code ();
/* ... */
}
As I’ve pointed out before in the c++filt
table the seemingly extraneous or weird instructions +30
to +43
are utilizing the interchaining ability of the <<
operator, now onto get_code
:
0x0000000008001329 <+0>: push %rbp
0x000000000800132a <+1>: mov %rsp,%rbp
0x000000000800132d <+4>: sub $0x10,%rsp
0x0000000008001331 <+8>: movl $0x0,-0x4(%rbp)
0x0000000008001338 <+15>: cmpl $0x3,-0x4(%rbp)
0x000000000800133c <+19>: jg 0x80013b2 <_Z8get_codev+137>
0x000000000800133e <+21>: lea 0xcf1(%rip),%rsi # 0x8002036
0x0000000008001345 <+28>: lea 0x2e34(%rip),%rdi # 0x8004180 <_ZSt4cout@@GLIBCXX_3.4>
0x000000000800134c <+35>: callq 0x8001050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x0000000008001351 <+40>: mov %rax,%rdx
0x0000000008001354 <+43>: mov -0x4(%rbp),%eax
0x0000000008001357 <+46>: add $0x1,%eax
0x000000000800135a <+49>: mov %eax,%esi
0x000000000800135c <+51>: mov %rdx,%rdi
0x000000000800135f <+54>: callq 0x8001090 <_ZNSolsEi@plt>
0x0000000008001364 <+59>: lea 0xcd8(%rip),%rsi # 0x8002043
0x000000000800136b <+66>: mov %rax,%rdi
0x000000000800136e <+69>: callq 0x8001050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x0000000008001373 <+74>: mov -0x4(%rbp),%eax
0x0000000008001376 <+77>: cltq
0x0000000008001378 <+79>: lea 0x0(,%rax,4),%rdx
0x0000000008001380 <+87>: lea 0x3039(%rip),%rax # 0x80043c0 <code>
0x0000000008001387 <+94>: add %rdx,%rax
0x000000000800138a <+97>: mov %rax,%rsi
0x000000000800138d <+100>: lea 0x2f0c(%rip),%rdi # 0x80042a0 <_ZSt3cin@@GLIBCXX_3.4>
0x0000000008001394 <+107>: callq 0x8001030 <_ZNSirsERi@plt>
0x0000000008001399 <+112>: lea 0xca6(%rip),%rsi # 0x8002046
0x00000000080013a0 <+119>: lea 0x2dd9(%rip),%rdi # 0x8004180 <_ZSt4cout@@GLIBCXX_3.4>
0x00000000080013a7 <+126>: callq 0x8001050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x00000000080013ac <+131>: addl $0x1,-0x4(%rbp)
0x00000000080013b0 <+135>: jmp 0x8001338 <_Z8get_codev+15>
0x00000000080013b2 <+137>: lea 0x3007(%rip),%rax # 0x80043c0 <code>
0x00000000080013b9 <+144>: leaveq
0x00000000080013ba <+145>: retq
+8
to +19
indicate that we are dealing with a for-loop (since +131
), having already run the crackme it is helpful to pay note that at the surface of the program this function most likely will iterate four times, (hence the jg
and not jge
) and ask for a digit from the user:
int code[4] = {0};
int[4]
get_code ()
{
size_t iter;
for (iter = 0; iter <= 3; ++iter)
{
std::cout << "Enter Digit " << iter + 1 << ": ";
std::cin >> code[iter];
std::cout << "\n";
}
return code;
}
Something more interesting about reading binary C++ is that the mangled names are genuinely useful in the case of manual type inference, like for example, the code
variable being an array of four integers may have been size_t
or any other qualifiable type as far as I’m concerned but the name: _ZNSirsERi
gave it away, as it translates to std::basic_istream<char, std::char_traits<char> >::operator>>(int&)
where the int&
most likely suggests that code
is an integer array, as int&
is a reference to an integer, which is what is fed into the code
variable as it is indexed 4-bytes at a time.
0x00000000080011ca <+53>: mov %rax,-0x10(%rbp)
0x00000000080011ce <+57>: lea 0x31eb(%rip),%rdi # 0x80043c0 <code>
0x00000000080011d5 <+64>: callq 0x8001265 <_Z10check_codePi>
0x00000000080011da <+69>: xor $0x1,%eax
0x00000000080011dd <+72>: test %al,%al
0x00000000080011df <+74>: je 0x80011fe <main+105>
0x00000000080011e1 <+76>: lea 0xe38(%rip),%rsi # 0x8002020
0x00000000080011e8 <+83>: lea 0x2f91(%rip),%rdi # 0x8004180 <_ZSt4cout@@GLIBCXX_3.4>
0x00000000080011ef <+90>: callq 0x8001050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x00000000080011f4 <+95>: mov $0x0,%edi
0x00000000080011f9 <+100>: callq 0x8001070 <exit@plt>
Translates to:
int
main ()
{
std::cout << "Please Enter The Passcode:" << std::endl;
int UNUSED[4] = get_code ();
UNKNOWN ret = check_code (code);
if (ret ^ 1)
{
std::cout << "\nWRONG\n";
exit (0);
}
/* ... */
}
And following through:
0x00000000080011fe <+105>: lea 0xe23(%rip),%rsi # 0x8002028
0x0000000008001205 <+112>: lea 0x2f74(%rip),%rdi # 0x8004180 <_ZSt4cout@@GLIBCXX_3.4>
0x000000000800120c <+119>: callq 0x8001050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x0000000008001211 <+124>: movl $0x0,-0x4(%rbp)
0x0000000008001218 <+131>: cmpl $0x3,-0x4(%rbp)
0x000000000800121c <+135>: jg 0x8001248 <main+179>
0x000000000800121e <+137>: mov -0x4(%rbp),%eax
0x0000000008001221 <+140>: cltq
0x0000000008001223 <+142>: lea 0x0(,%rax,4),%rdx
0x000000000800122b <+150>: mov -0x10(%rbp),%rax
0x000000000800122f <+154>: add %rdx,%rax
0x0000000008001232 <+157>: mov (%rax),%eax
0x0000000008001234 <+159>: mov %eax,%esi
0x0000000008001236 <+161>: lea 0x2f43(%rip),%rdi # 0x8004180 <_ZSt4cout@@GLIBCXX_3.4>
0x000000000800123d <+168>: callq 0x8001090 <_ZNSolsEi@plt>
0x0000000008001242 <+173>: addl $0x1,-0x4(%rbp)
0x0000000008001246 <+177>: jmp 0x8001218 <main+131>
0x0000000008001248 <+179>: mov 0x2d81(%rip),%rax # 0x8003fd0
0x000000000800124f <+186>: mov %rax,%rsi
0x0000000008001252 <+189>: lea 0x2f27(%rip),%rdi # 0x8004180 <_ZSt4cout@@GLIBCXX_3.4>
0x0000000008001259 <+196>: callq 0x8001060 <_ZNSolsEPFRSoS_E@plt>
0x000000000800125e <+201>: mov $0x0,%eax
0x0000000008001263 <+206>: leaveq
0x0000000008001264 <+207>: retq
Gives:
int
main ()
{
std::cout << "Please Enter The Passcode:" << std::endl;
int codes[4] = get_code ();
UNKNOWN ret = check_code (code);
if (ret ^ 1)
{
std::cout << "\nWRONG\n";
exit (0);
}
std::cout << "\nYou Did it.\n"
size_t iter;
for (iter = 0; iter <= 3; ++iter)
{
std::cout << codes[iter];
}
std::cout << std::endl;
return 0;
}
And so, it seems the only other relevant function to analyze is check_code
(obviously):
0x0000000008001265 <+0>: push %rbp
0x0000000008001266 <+1>: mov %rsp,%rbp
0x0000000008001269 <+4>: push %rbx
0x000000000800126a <+5>: sub $0x18,%rsp
0x000000000800126e <+9>: mov %rdi,-0x18(%rbp)
0x0000000008001272 <+13>: mov -0x18(%rbp),%rax
0x0000000008001276 <+17>: mov (%rax),%ebx
0x0000000008001278 <+19>: mov $0xa,%esi
0x000000000800127d <+24>: lea 0x2dfc(%rip),%rdi # 0x8004080 <p1>
0x0000000008001284 <+31>: callq 0x80013bb <_Z9get_digitPii>
0x0000000008001289 <+36>: cmp %eax,%ebx
0x000000000800128b <+38>: setne %al
0x000000000800128e <+41>: test %al,%al
0x0000000008001290 <+43>: je 0x800129c <_Z10check_codePi+55>
0x0000000008001292 <+45>: mov $0x0,%eax
0x0000000008001297 <+50>: jmpq 0x8001322 <_Z10check_codePi+189>
0x000000000800129c <+55>: mov -0x18(%rbp),%rax
0x00000000080012a0 <+59>: add $0x4,%rax
0x00000000080012a4 <+63>: mov (%rax),%ebx
0x00000000080012a6 <+65>: mov $0xa,%esi
0x00000000080012ab <+70>: lea 0x2e0e(%rip),%rdi # 0x80040c0 <p2>
0x00000000080012b2 <+77>: callq 0x80013bb <_Z9get_digitPii>
0x00000000080012b7 <+82>: cmp %eax,%ebx
0x00000000080012b9 <+84>: setne %al
0x00000000080012bc <+87>: test %al,%al
0x00000000080012be <+89>: je 0x80012c7 <_Z10check_codePi+98>
0x00000000080012c0 <+91>: mov $0x0,%eax
0x00000000080012c5 <+96>: jmp 0x8001322 <_Z10check_codePi+189>
0x00000000080012c7 <+98>: mov -0x18(%rbp),%rax
0x00000000080012cb <+102>: add $0x8,%rax
0x00000000080012cf <+106>: mov (%rax),%ebx
0x00000000080012d1 <+108>: mov $0xa,%esi
0x00000000080012d6 <+113>: lea 0x2e23(%rip),%rdi # 0x8004100 <p3>
0x00000000080012dd <+120>: callq 0x80013bb <_Z9get_digitPii>
0x00000000080012e2 <+125>: cmp %eax,%ebx
0x00000000080012e4 <+127>: setne %al
0x00000000080012e7 <+130>: test %al,%al
0x00000000080012e9 <+132>: je 0x80012f2 <_Z10check_codePi+141>
0x00000000080012eb <+134>: mov $0x0,%eax
0x00000000080012f0 <+139>: jmp 0x8001322 <_Z10check_codePi+189>
0x00000000080012f2 <+141>: mov -0x18(%rbp),%rax
0x00000000080012f6 <+145>: add $0xc,%rax
0x00000000080012fa <+149>: mov (%rax),%ebx
0x00000000080012fc <+151>: mov $0xa,%esi
0x0000000008001301 <+156>: lea 0x2e38(%rip),%rdi # 0x8004140 <p4>
0x0000000008001308 <+163>: callq 0x80013bb <_Z9get_digitPii>
0x000000000800130d <+168>: cmp %eax,%ebx
0x000000000800130f <+170>: setne %al
0x0000000008001312 <+173>: test %al,%al
0x0000000008001314 <+175>: je 0x800131d <_Z10check_codePi+184>
0x0000000008001316 <+177>: mov $0x0,%eax
0x000000000800131b <+182>: jmp 0x8001322 <_Z10check_codePi+189>
0x000000000800131d <+184>: mov $0x1,%eax
0x0000000008001322 <+189>: add $0x18,%rsp
0x0000000008001326 <+193>: pop %rbx
0x0000000008001327 <+194>: pop %rbp
0x0000000008001328 <+195>: retq
Beginning with:
0x0000000008001265 <+0>: push %rbp
0x0000000008001266 <+1>: mov %rsp,%rbp
0x0000000008001269 <+4>: push %rbx
0x000000000800126a <+5>: sub $0x18,%rsp
0x000000000800126e <+9>: mov %rdi,-0x18(%rbp)
0x0000000008001272 <+13>: mov -0x18(%rbp),%rax
0x0000000008001276 <+17>: mov (%rax),%ebx
0x0000000008001278 <+19>: mov $0xa,%esi
0x000000000800127d <+24>: lea 0x2dfc(%rip),%rdi # 0x8004080 <p1>
0x0000000008001284 <+31>: callq 0x80013bb <_Z9get_digitPii>
0x0000000008001289 <+36>: cmp %eax,%ebx
0x000000000800128b <+38>: setne %al
0x000000000800128e <+41>: test %al,%al
0x0000000008001290 <+43>: je 0x800129c <_Z10check_codePi+55>
0x0000000008001292 <+45>: mov $0x0,%eax
0x0000000008001297 <+50>: jmpq 0x8001322 <_Z10check_codePi+189>
Translates trivially to:
UNKNOWN
check_code (int codes[4])
{
if (codes[0] != get_digit (p1, 0xa))
{
return 1;
}
/* ... */
}
In fact, the function is quite easy:
0x000000000800129c <+55>: mov -0x18(%rbp),%rax
0x00000000080012a0 <+59>: add $0x4,%rax
0x00000000080012a4 <+63>: mov (%rax),%ebx
0x00000000080012a6 <+65>: mov $0xa,%esi
0x00000000080012ab <+70>: lea 0x2e0e(%rip),%rdi # 0x80040c0 <p2>
0x00000000080012b2 <+77>: callq 0x80013bb <_Z9get_digitPii>
0x00000000080012b7 <+82>: cmp %eax,%ebx
0x00000000080012b9 <+84>: setne %al
0x00000000080012bc <+87>: test %al,%al
0x00000000080012be <+89>: je 0x80012c7 <_Z10check_codePi+98>
0x00000000080012c0 <+91>: mov $0x0,%eax
0x00000000080012c5 <+96>: jmp 0x8001322 <_Z10check_codePi+189>
0x00000000080012c7 <+98>: mov -0x18(%rbp),%rax
0x00000000080012cb <+102>: add $0x8,%rax
0x00000000080012cf <+106>: mov (%rax),%ebx
0x00000000080012d1 <+108>: mov $0xa,%esi
0x00000000080012d6 <+113>: lea 0x2e23(%rip),%rdi # 0x8004100 <p3>
0x00000000080012dd <+120>: callq 0x80013bb <_Z9get_digitPii>
0x00000000080012e2 <+125>: cmp %eax,%ebx
0x00000000080012e4 <+127>: setne %al
0x00000000080012e7 <+130>: test %al,%al
0x00000000080012e9 <+132>: je 0x80012f2 <_Z10check_codePi+141>
0x00000000080012eb <+134>: mov $0x0,%eax
0x00000000080012f0 <+139>: jmp 0x8001322 <_Z10check_codePi+189>
0x00000000080012f2 <+141>: mov -0x18(%rbp),%rax
0x00000000080012f6 <+145>: add $0xc,%rax
0x00000000080012fa <+149>: mov (%rax),%ebx
0x00000000080012fc <+151>: mov $0xa,%esi
0x0000000008001301 <+156>: lea 0x2e38(%rip),%rdi # 0x8004140 <p4>
0x0000000008001308 <+163>: callq 0x80013bb <_Z9get_digitPii>
0x000000000800130d <+168>: cmp %eax,%ebx
0x000000000800130f <+170>: setne %al
0x0000000008001312 <+173>: test %al,%al
0x0000000008001314 <+175>: je 0x800131d <_Z10check_codePi+184>
0x0000000008001316 <+177>: mov $0x0,%eax
0x000000000800131b <+182>: jmp 0x8001322 <_Z10check_codePi+189>
0x000000000800131d <+184>: mov $0x1,%eax
0x0000000008001322 <+189>: add $0x18,%rsp
0x0000000008001326 <+193>: pop %rbx
0x0000000008001327 <+194>: pop %rbp
0x0000000008001328 <+195>: retq
Gives:
bool
check_code (int codes[4])
{
if ((codes[0] != get_digit (p1, 0xa)) ||
(codes[1] != get_digit (p2, 0xa)) ||
(codes[2] != get_digit (p3, 0xa)) ||
(codes[3] != get_digit (p4, 0xa)))
{
return 1;
}
return 0;
}
And so we can see the ultimate function we need is get_digit
:
0x00000000080013bb <+0>: push %rbp
0x00000000080013bc <+1>: mov %rsp,%rbp
0x00000000080013bf <+4>: mov %rdi,-0x18(%rbp)
0x00000000080013c3 <+8>: mov %esi,-0x1c(%rbp)
0x00000000080013c6 <+11>: movl $0x0,-0x4(%rbp)
0x00000000080013cd <+18>: movl $0x0,-0x8(%rbp)
0x00000000080013d4 <+25>: movl $0x0,-0xc(%rbp)
0x00000000080013db <+32>: mov -0xc(%rbp),%eax
0x00000000080013de <+35>: cmp -0x1c(%rbp),%eax
0x00000000080013e1 <+38>: jge 0x8001435 <_Z9get_digitPii+122>
0x00000000080013e3 <+40>: mov -0xc(%rbp),%eax
0x00000000080013e6 <+43>: cltq
0x00000000080013e8 <+45>: lea 0x0(,%rax,4),%rdx
0x00000000080013f0 <+53>: mov -0x18(%rbp),%rax
0x00000000080013f4 <+57>: add %rdx,%rax
0x00000000080013f7 <+60>: mov (%rax),%eax
0x00000000080013f9 <+62>: and -0x4(%rbp),%eax
0x00000000080013fc <+65>: or %eax,-0x8(%rbp)
0x00000000080013ff <+68>: mov -0xc(%rbp),%eax
0x0000000008001402 <+71>: cltq
0x0000000008001404 <+73>: lea 0x0(,%rax,4),%rdx
0x000000000800140c <+81>: mov -0x18(%rbp),%rax
0x0000000008001410 <+85>: add %rdx,%rax
0x0000000008001413 <+88>: mov (%rax),%eax
0x0000000008001415 <+90>: xor %eax,-0x4(%rbp)
0x0000000008001418 <+93>: mov -0x4(%rbp),%eax
0x000000000800141b <+96>: and -0x8(%rbp),%eax
0x000000000800141e <+99>: not %eax
0x0000000008001420 <+101>: mov %eax,-0x10(%rbp)
0x0000000008001423 <+104>: mov -0x10(%rbp),%eax
0x0000000008001426 <+107>: and %eax,-0x4(%rbp)
0x0000000008001429 <+110>: mov -0x10(%rbp),%eax
0x000000000800142c <+113>: and %eax,-0x8(%rbp)
0x000000000800142f <+116>: addl $0x1,-0xc(%rbp)
0x0000000008001433 <+120>: jmp 0x80013db <_Z9get_digitPii+32>
0x0000000008001435 <+122>: mov -0x4(%rbp),%eax
0x0000000008001438 <+125>: pop %rbp
0x0000000008001439 <+126>: retq
Feel like disassembling this? Me neither, we can just set $rip
our way through the check_code
function instead of trying to figure out what this does:
(gdb) print $eax
$1 = 3
[...]
(gdb) print $eax
$2 = 6
[...]
(gdb) print $eax
$3 = 7
[...]
(gdb) print $rax
$4 = 4
Et, voila:
>./crack3-by-D4RK_FL0W
Please Enter The Passcode:
Enter Digit 1: 3
Enter Digit 2: 6
Enter Digit 3: 7
Enter Digit 4: 4
You Did It.
3674
Thanks for reading.