1

it's me again. I am working on a tool can that disassemble/reassemble stripped binaries and now I am sucked in a (external) symbol reuse issue.

The test is on 32-bit Linux x86 platform.

Suppose I am working on a C++ program, in the GCC compiler produced assembly code, there exists some instructions like this:

call    _ZNSt8ios_baseC2Ev
movl    _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE+4, %ebx
movb    $0, 312(%esp)
movl    _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE+8, %ecx
....

Please pay special attention to symbol _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE.

After the compilation, suppose I get an unstripped binary, and i checked this symbol like this:

readelf -s a.out | grep "_ZTTSt14basic"
69: 080a7390    16 OBJECT  WEAK   DEFAULT   27 _ZTTSt14basic_ifstreamIcS@GLIBCXX_3.4 (3)
72: 080a7220    16 OBJECT  WEAK   DEFAULT   27 _ZTTSt14basic_ofstreamIcS@GLIBCXX_3.4 (3)
705: 080a7220    16 OBJECT  WEAK   DEFAULT   27 _ZTTSt14basic_ofstreamIcS
1033: 080a7390    16 OBJECT  WEAK   DEFAULT   27 _ZTTSt14basic_ifstreamIcS

See, this is my first question, why the name of symbol _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE modified to _ZTTSt14basic_ifstreamIcS and _ZTTSt14basic_ifstreamIcS@GLIBCXX_3.4 (3) ?

What is _ZTTSt14basic_ifstreamIcS@GLIBCXX_3.4 (3) though?

Then I stripped the binary like this:

strip a.out
readelf -s a.out | grep "_ZTTSt14basic"
69: 080a7390    16 OBJECT  WEAK   DEFAULT   27 _ZTTSt14basic_ifstreamIcS@GLIBCXX_3.4 (3)
72: 080a7220    16 OBJECT  WEAK   DEFAULT   27 _ZTTSt14basic_ofstreamIcS@GLIBCXX_3.4 (3)

Then after I disassemble the binary, and the corresponding disassembled assembly instructions are :

 8063ee7:       e8 84 54 fe ff          call   8049370 <_ZNSt8ios_baseC2Ev@plt>
 8063eec:       8b 1d 94 73 0a 08       mov    0x80a7394,%ebx
 8063ef2:       c6 84 24 38 01 00 00    movb   $0x0,0x138(%esp)
 8063ef9:       00
 8063efa:       8b 0d 98 73 0a 08       mov    0x80a7398,%ecx

At this point we can figure out that 0x80a7394 equals to _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE+4.

In order to reuse these instructions, I modified the code:

call _ZNSt8ios_baseC2Ev
mov _ZTTSt14basic_ifstreamIcS+4,%ebx
movb $0x0,0x138(%esp)
mov _ZTTSt14basic_ifstreamIcS+8,%ecx

And did some update like these (please see this question for reference):

echo ""_ZTTSt14basic_ifstreamIcS@GLIBCXX_3.4 (3)" = 0x080a7390;" > symbolfile
g++ -Wl,--just-symbols=symbolfile  final.s

readelf -s a.out | grep "_ZTTSt14basic"

3001: 080a7390     0 NOTYPE  LOCAL  DEFAULT   27 _ZTTSt14basic_ifstreamIcS
8412: 080a7390     0 NOTYPE  GLOBAL DEFAULT  ABS _ZTTSt14basic_ifstreamIcS

I debugged the newly produced binary, and to my surprise, in the newly produced binary, symbol _ZTTSt14basic_ifstreamIcS does not get any value after the function call of _ZNSt8ios_baseC2Ev, while in the original binary, after the function call, _ZTTSt14basic_ifstreamIcS do get some memory address referring to library section. Which means:

call _ZNSt8ios_baseC2Ev
mov _ZTTSt14basic_ifstreamIcS+4,%ebx  <--- %ebx gets zero!
movb $0x0,0x138(%esp)
mov _ZTTSt14basic_ifstreamIcS+8,%ecx  <--- %ecx gets zero!

I must state that in these lines of the original binary, registers %ebx and %ecx both gets some addresses referring to the libc section.

This is my second question, why does symbol _ZTTSt14basic_ifstreamIcS didn't get any value after function call _ZNSt8ios_baseC2Ev? I also tried with symbol name _ZTTSt14basic_ifstreamIcSt11char_traitsIcEE. But that does not work also.

Am I clear enough? Could anyone save my ass? thank you!

Community
  • 1
  • 1
lllllllllllll
  • 8,519
  • 9
  • 45
  • 80

0 Answers0