paralax
paralax

Reputation: 31

Intel PIN Routine address retrieval: Linux vs. Windows

I'm new to PIN so perhaps there is an easy explanation to this. I'm puzzled by routine addresses PIN returns on Windows only. I created a minimal test program to illustrate my point.

I'm currently using PIN 2.14. My inspected application is a Debug build, with disabled ASLR on Windows.

First consider this simple application that calls an empty method and prints the method's address:

#include "stdio.h"
class Test {
public:
  void method() {}
};
void main() {
  Test t;
  t.method();
  printf("Test::method = 0x%p\n", &Test::method);
}

The following pin tool will disassemble a program's main routine and print the address of Test::method:

#include <pin.H>
#include "stdio.h"
VOID disassemble(IMG img, VOID *v)
{
  for (SEC sec = IMG_SecHead(img); SEC_Valid(sec); sec = SEC_Next(sec))
  {
    for (RTN rtn = SEC_RtnHead(sec); RTN_Valid(rtn); rtn = RTN_Next(rtn))
    {
      auto name = RTN_Name(rtn);
      if(name == "Test::method" || name == "_ZN4Test6methodEv") {
        printf("%s detected by PIN resides at 0x%p.\n", name.c_str(), RTN_Address(rtn));
      }
      if (RTN_Name(rtn) != "main") continue;
      RTN_Open(rtn);
      for (INS ins = RTN_InsHead(rtn); INS_Valid(ins); ins = INS_Next(ins))     {
        printf("%s\n", INS_Disassemble(ins).c_str());
      }
      RTN_Close(rtn);
    }
  }
}
int main(int argc, char **argv)
{
  PIN_InitSymbols();
  PIN_Init(argc, argv);
  IMG_AddInstrumentFunction(disassemble, 0);
  PIN_StartProgram();
  return 0;
}

Running this PIN tool against the test application on an Ubuntu 14.04.3 x64 VM prints:

push rbp
mov rbp, rsp
push r13
push r12
push rbx
sub rsp, 0x18
lea rax, ptr [rbp-0x21]
mov rdi, rax
call 0x400820
mov r12d, 0x400820
mov r13d, 0x0
mov rcx, r12
mov rbx, r13
mov rax, r12
mov rdx, r13
mov rax, rdx
mov rsi, rcx
mov rdx, rax
mov edi, 0x4008b4
mov eax, 0x0
call 0x4006a0
mov eax, 0x0
add rsp, 0x18
pop rbx
pop r12
pop r13
pop rbp
ret 
_ZN4Test6methodEv detected by PIN resides at 0x0x400820.
Test::method = 0x0x400820

Please note that both the call targeting t.method(), as well as the function address retrieved by PIN and the application's output show Test::method to reside at address 0x0x400820.

The output on my Windows 10 x64 machine is:

push rdi
sub rsp, 0x40
mov rdi, rsp
mov ecx, 0x10
mov eax, 0xcccccccc
rep stosd dword ptr [rdi]
lea rcx, ptr [rsp+0x24]
call 0x14000104b
lea rdx, ptr [rip-0x2b]
lea rcx, ptr [rip+0x74ca3]
call 0x1400013f0
xor eax, eax
mov edi, eax
mov rcx, rsp
lea rdx, ptr [rip+0x74cf0]
call 0x1400015f0
mov eax, edi
add rsp, 0x40
pop rdi
ret
Test::method detected by PIN resides at 0x0000000140001120.
Test::method = 0x000000014000104B

The application's output and the call target in the disassembly show the same value. However the routine address returned by PIN is different!
I'm very puzzled about this behavior. Do you have any idea how to explain this?

Thanks for any suggestions!

Upvotes: 2

Views: 267

Answers (1)

paralax
paralax

Reputation: 31

Answering my question for myself:

After probing for a while it became evident that both function pointers, the call target as well as the routine address returned by PIN were valid and ended up calling the method.

I ended up looking at the in-memory diassembly of my call target's address and sure enough it looked something like this:

0000000140001122 E9 D2 00 00 00       jmp         Test::method (014000104Bh)  

In other words: PIN seemingly replaced the original method with a jump to its own version of the code. Knowing this, correlating original function pointers and PIN routine addresses again became possible which is all I needed to do.

Upvotes: 1

Related Questions