2

I'm trying to solve a crackme that was made in C++, and I was able to "recreate" a function call, through the library calls the program made. Here's the piece of code that I'm trying to reverse:

string text;
getline(cin, text);

And here's the asm equivalent (getline only):

lea    rax,[rbp-0x1c0]
mov    rsi,rax
mov    edi,0x6020c0
call   0x400d10 <std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)@plt>

What is happening with the variable text (Meaning: I can't seem to print the place in memory in which the raw characters are stored)? I'm using print *(char **)<register/memory> to try to find it. Where are the raw characters of this string stored after this operation? How to I find it and how to I print them?

I'm using gdb.

3

use print &text
or use info locals

:\>dir /b & type cin.cpp & g++ -g cin.cpp  & echo ========= & gdb -q a.exe
cin.cpp
#include <iostream>
#include <string>
using namespace std;    
int main (void) {
    string text;
    getline(cin,text);
}=========
Reading symbols from a.exe...done.
(gdb) break main
Breakpoint 1 at 0x4015cf: file cin.cpp, line 6.
(gdb) r
Breakpoint 1, main () at cin.cpp:6
6           string text;
(gdb) print &text
$1 = (std::__cxx11::string *) 0x22fec8  <<<<<<
(gdb) print text
$2 = ""ÿ\"\000lí|w", '\000' <repeats 12 times>,<repeats 11 times>...
(gdb) ni till getline is es=xecuted
0x004015e9      7           getline(cin,text);
(gdb)
hello cin where are you hiding
6           string text;
(gdb) print text
$3 = "hello cin where are you hiding"
(gdb) x/s $1
0x22fec8:       "ès2"
(gdb) x/s *(int *)$1
0x329ae8:       "hello cin where are you hiding"
(gdb) x/s *(int *)&text
0x329ae8:       "hello cin where are you hiding"
(gdb) info locals
text = "hello cin where are you hiding"

64 bit mingw64 on windows 10 (first four arguments are passed in ecx,edx,r8,r9. rest in stack)

source compiled without -g

cat.exe gppcpp.cpp
#include <iostream>
#include <string>
using namespace std;
int main(void) {
        string text;
        getline(cin, text);
}

compiled without debug info

g++ gppcpp.cpp

a.exe
555

disassembling function main using a file command.txt which contains the following commands

cat.exe commands.txt
set disassembly-flavor intel
set print asm-demangle on
break main
r
disassemble $pc
q

disassembly of main

:\>gdb -batch -x commands.txt a.exe

Breakpoint 1 at 0x401563
[New Thread 8964.0x2c38]

Breakpoint 1, 0x0000000000401563 in main ()
Dump of assembler code for function main:
   0x0000000000401550 <+0>:     push   rbp
   0x0000000000401551 <+1>:     push   rbx
   0x0000000000401552 <+2>:     sub    rsp,0x48
   0x0000000000401556 <+6>:     lea    rbp,[rsp+0x80]
   0x000000000040155e <+14>:    call   0x401710 <__main>
=> 0x0000000000401563 <+19>:    lea    rax,[rbp-0x60]
   0x0000000000401567 <+23>:    mov    rcx,rax
   0x000000000040156a <+26>:    call   0x401658 <std::__cxx11::basic_stringxxxxxxxxxxxx
   0x000000000040156f <+31>:    lea    rax,[rbp-0x60]
   0x0000000000401573 <+35>:    mov    rdx,rax
   0x0000000000401576 <+38>:    mov    rcx,QWORD PTR [rip+0x2d93]
   0x000000000040157d <+45>:    call   0x401638 <std::basic_istream<char, std::cxxxxxxxxxxxx
   0x0000000000401582 <+50>:    lea    rax,[rbp-0x60]
   0x0000000000401586 <+54>:    mov    rcx,rax
   0x0000000000401589 <+57>:    call   0x401650 <std::__cxx11::basic_string<char,xxxxxxx
   0x000000000040158e <+62>:    mov    eax,0x0
   0x0000000000401593 <+67>:    jmp    0x4015af <main+95>
   0x0000000000401595 <+69>:    mov    rbx,rax
   0x0000000000401598 <+72>:    lea    rax,[rbp-0x60]
   0x000000000040159c <+76>:    mov    rcx,rax
   0x000000000040159f <+79>:    call   0x401650 <std::__cxx11::basic_string<char,xxxxxxxxxxxx
   0x00000000004015a4 <+84>:    mov    rax,rbx
   0x00000000004015a7 <+87>:    mov    rcx,rax
   0x00000000004015aa <+90>:    call   0x402ae0 <_Unwind_Resume>
   0x00000000004015af <+95>:    add    rsp,0x48
   0x00000000004015b3 <+99>:    pop    rbx
   0x00000000004015b4 <+100>:   pop    rbp
   0x00000000004015b5 <+101>:   ret
End of assembler dump.
A debugging session is active.

        Inferior 1 [process 8964] will be killed.

Quit anyway? (y or n) [answered Y; input not from terminal

the second argument is @rdx
lets debug step few times until $rdx is initialized
save it and execute the getline and retrieve the cin from saved variable

:\>gdb -q a.exe
Reading symbols from a.exe...done.

(gdb) break main
Breakpoint 1 at 0x401563

(gdb) r
Starting program: F:\src\gppcpp\a.exe
[New Thread 6832.0x13c4]
Breakpoint 1, 0x0000000000401563 in main ()

(gdb) ni 6
0x000000000040157d in main ()

(gdb) set print  asm-demangle on

(gdb) x/i $pc
=> 0x40157d <main+45>:
    callq  0x401638 <std::basic_istream<char, xxxxxxxxxx

(gdb) print $rdx
$1 = 6422000

(gdb) ni
hello uncanny the cin is at saved variable $1

0x0000000000401582 in main ()

(gdb) x/s *(char **)$1
0x143a60:       "hello uncanny the cin is at saved variable $1"
(gdb)
3
  • 1
    Hey man, I'm new to reverse engineering so I'm kinda lost in your answer. The crackme I'm trying to solve is not compiled with the -g flag, so I don't have access to variable names and whatnot. The C++ code is what I found to be the representation of the asm code, through the library's calls, so how would I do that in that situation? Another thing is that your answer, IMHO, is really confusing for someone who's new, like me. :( Could you explain what is happening here? Thx a lot! – unc4nny Sep 14 '19 at 13:57
  • This answer relies on the internal structure of std::string. GDB should have built in pretty printing of STL structure, that should be used instead. – user202729 Sep 14 '19 at 16:10
  • removed comments and added content to answer – blabb Sep 17 '19 at 18:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.