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.

1 Answer 1

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
    Commented Sep 14, 2019 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
    Commented Sep 14, 2019 at 16:10
  • removed comments and added content to answer
    – blabb
    Commented Sep 17, 2019 at 18:39

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