Пин intel: процедура анализа обнаруживает регистрацию вместо rsp (REG_STACK_PTR) - PullRequest
2 голосов
/ 27 марта 2019

Я задал этот вопрос несколько дней назад.

Я хотел получить размер выделения стека (после создания функции). Ответ предлагает сделать:

if((INS_Opcode(ins) == XED_ICLASS_ADD || INS_Opcode(ins) == XED_ICLASS_SUB) && 
   REG(INS_OperandReg(ins, 0)) == REG_STACK_PTR && INS_OperandIsImmediate(ins, 1)

Что в теории правильно и имеет смысл. Но на практике это не работает (поправьте меня, если я здесь не прав). Он отлично работает, если я уберу REG(INS_OperandReg(ins, 0)) == REG_STACK_PTR check. Зачем? Поскольку pin не обнаруживает регистр REG_STACK_PTR, когда REG(INS_OperandReg(ins, 0)) используется для его обнаружения. скорее, он обнаруживает ah (который я считаю RAX), когда я проверяю по инструкции add rsp, 0xffffffffffffff80 (так, каждый раз, когда она дает: register: ah), как видно из моего вывода ниже:

in
register: rbp
40051e  push rbp
register: *invalid*
value: -128
40051f  mov rbp, rsp
register: ah
400522  add rsp, 0xffffffffffffff80
register: *invalid*
400526  mov dword ptr [rbp-0x28], 0x7
register: *invalid*
40052d  mov dword ptr [rbp-0x64], 0x9
register: eax
400534  mov eax, 0x0
register: *invalid*
400539  call 0x4004e6
register: rbp
4004e6  push rbp
register: *invalid*
value: 64
4004e7  mov rbp, rsp
register: ah
4004ea  sub rsp, 0x40
register: *invalid*
4004ee  mov dword ptr [rbp-0xc], 0x4
register: rax
4004f5  lea rax, ptr [rbp-0xc]
register: *invalid*
4004f9  mov qword ptr [rbp-0x8], rax
register: rax
4004fd  mov rax, qword ptr [rbp-0x8]
register: eax
400501  mov eax, dword ptr [rax]
register: *invalid*
400503  mov esi, eax
register: edi
400505  mov edi, 0x4005d0
register: eax
40050a  mov eax, 0x0
register: rdi
40050f  call 0x4003f0
register: rdi
4003f0  jmp qword ptr [rip+0x200c22]
register: *invalid*
4003f6  push 0x0
register: *invalid*
4003fb  jmp 0x4003e0
register: *invalid*
4003e0  push qword ptr [rip+0x200c22]
register: rdi
4003e6  jmp qword ptr [rip+0x200c24]
4
register: *invalid*
400514  mov dword ptr [rbp-0x3c], 0x3
40051b  nop
register: *invalid*
40051c  leave 
register: *invalid*
40051d  ret 
register: eax
40053e  mov eax, 0x0
register: *invalid*
400543  leave 
out

Интересно, что он делает это для каждого вхождения rsp (то есть обнаруживает ah вместо rsp). Кроме того, он всегда печатает инструкцию 400522 add rsp, 0xffffffffffffff80, включая rsp (Итак, почему здесь не печатается ah?)

Если ah представляет собой rsp, то я всегда могу определить ah, используя: REG(INS_OperandReg(ins, 0)) == REG_AH. Но я хочу понять, что здесь происходит.

Мой код:

#include <iostream>
#include <fstream>
#include "pin.H"
#include <unordered_map>

// key to open the main Routine
static uint32_t key = 0;

// Ins object mapping
class Insr
{
private:
  // Disassembled instruction
    string insDis;
  INS ins;

public:
    Insr(string insDis, INS ins) { this->insDis = insDis; this->ins = ins;}
    string get_insDis() { return insDis;}
  INS get_ins() { return ins;}
};

// Stack for the Insr structure
static std::unordered_map<ADDRINT, Insr*> insstack;

// This function is called before every instruction is executed
VOID protect(uint64_t addr)
{
  if (addr > 0x700000000000)
        return;
    if (!key)
        return;
  // Initialize the diassembled instruction
  string insdis = insstack[addr]->get_insDis();
  INS ins = insstack[addr]->get_ins();
    if (INS_OperandCount(ins) > 0)
    {
        if (REG(INS_OperandReg(ins, 0)) == REG_AH)
            std::cout << "register: " << REG_StringShort(REG(INS_OperandReg(ins, 0))) << '\n';
    }

  if((INS_Opcode(ins) == XED_ICLASS_ADD || INS_Opcode(ins) == XED_ICLASS_SUB) &&
   INS_OperandIsImmediate(ins, 1))
    {
      int value = INS_OperandImmediate(ins, 1);
        std::cout << "value: " << dec<<value << '\n';
    }
  std::cout << hex <<addr << "\t" << insdis << std::endl;
}

// Pin calls this function every time a new instruction is encountered
VOID Instruction(INS ins, VOID *v)
{
        if (INS_Address(ins) > 0x700000000000)
        return;

    insstack.insert(std::make_pair(INS_Address(ins), new Insr(string(INS_Disassemble(ins)),
    ins)));
    // if (REG_valid_for_iarg_reg_value(INS_MemoryIndexReg(ins)))
    //   std::cout << "true" << '\n';
    // Insert a call to docount before every instruction, no arguments are passed
    INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)protect, IARG_ADDRINT, INS_Address(ins),
  IARG_END);
}

// Lock Routine
void mutex_lock()
{
key = 0;
std::cout<<"out\n";
}
void mutex_unlock()
{
    key = 1;
    std::cout<<"in\n";
}

void Routine(RTN rtn, VOID *V)
{
    if (RTN_Name(rtn) == "main")
    {
        RTN_Open(rtn);
        RTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)mutex_unlock, IARG_END);
        RTN_InsertCall(rtn, IPOINT_AFTER, (AFUNPTR)mutex_lock, IARG_END);
        RTN_Close(rtn);
    }
}

INT32 Usage()
{
    cerr << "This tool counts the number of dynamic instructions executed" << endl;
    cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
    return -1;
}

int main(int argc, char * argv[])
{
    // Initialize the symbol table
    PIN_InitSymbols();

    // Initialize pin
    if (PIN_Init(argc, argv)) return Usage();

    PIN_SetSyntaxIntel();

    // Routine instrumentation
    RTN_AddInstrumentFunction(Routine, 0);

    // Register Instruction to be called to instrument instructions
    INS_AddInstrumentFunction(Instruction, 0);

    // Start the program, never returns
    PIN_StartProgram();

    return 0;
}

У меня есть несколько вопросов по этому поводу.

Не могли бы вы помочь мне понять такое поведение? И как я могу обнаружить rsp, если я хочу? Наконец, как инструкция печатает rsp, но REG(INS_OperandReg(ins, 0)) == REG_STACK_PTR не может обнаружить его? Заранее спасибо.

1 Ответ

2 голосов
/ 27 марта 2019

Объекты INS действительны только внутри процедур КИПиА, таких как ваша подпрограмма Instruction. Тип INS - это не что иное, как 32-разрядное целое число, которое идентифицирует инструкцию. Среда выполнения Pin внутренне поддерживает таблицу, которая отображает эти 32-разрядные целые числа на конкретные статические инструкции. Он создает такую ​​таблицу всякий раз, когда собирается вызвать процедуру инструментирования. Когда процедура инструментария возвращается, нет никакой гарантии, что какой-либо из этих идентификаторов будет отображаться в одни и те же статические инструкции, и они могут даже быть недействительными. Поэтому, когда вы сохраняете копию объекта INS в следующей строке кода:

insstack.insert(std::make_pair(INS_Address(ins), new Insr(string(INS_Disassemble(ins)),
    ins)));

эта копия полезна только в том же экземпляре подпрограммы Instruction. В следующий раз, когда вызывается подпрограмма Instruction (или любая другая подпрограмма инструментария), идентификатор команды может быть повторно использован для других команд.

Если вы действительно хотите передать инструкцию в процедуру анализа, у вас есть два варианта:

  • Скопируйте действительные байты инструкции в буфер и передайте адрес буфера, а затем расшифруйте его, используя XED API.
  • Передайте адрес инструкции, а затем расшифруйте ее, используя XED API. Это работает, если инструкция гарантированно будет доступна в том же месте позже.
...