#include <stdio.h> #include "pin.H" // This function is called before every instruction is executed VOID corrupt(ADDRINT ip,ADDRINT ESP) { if (ip == 0x12B17D3) { *(ADDRINT *)ESP = 0x12B6EEC; } } // Pin calls this function every time a new instruction is encountered VOID Instruction(INS ins, VOID *v) { // Insert a call to printip before every instruction, and pass it the IP INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)corrupt, IARG_INST_PTR, IARG_REG_VALUE, REG_ESP, IARG_END); } /* ===================================================================== */ /* Main */ /* ===================================================================== */ int main(int argc, char * argv[]) { // Initialize pin if (PIN_Init(argc, argv)) return -1; // Register Instruction to be called to instrument instructions INS_AddInstrumentFunction(Instruction, 0); // Start the program, never returns PIN_StartProgram(); return 0; }
이 프로그램은 Hello World!를 출력하는 프로그램에 대해서 핀툴을 이용하여 Hello World!를 출력하는 대신 다른 문자열을 출력하는 소스이다. Hello World!를 출력하는 부분은 0x12B17D3에서 call 명령어가 실행되고 인자로 Hello World!문자열의 주소가 들어가서 Hello World!가 출력되게 된다. 이때 인자는 스택에 들어가게 되는데, 프로그램 흐름이 0x12B17D3으로 왔을 때 스택에 다른 문자열의 주소를 넣어주면 다른 문자열이 출력되게 할 수 있다. rdata 영역에 Hello World!라는 문자열이 들어가 있는데, rdata에 있는 다른 문자열, 여기서는 corrupted라는 문자열(주소: 0x12B6EEC)를 인자로 넣어주어서 corrupted가 출력되게끔 만들었다.
ADDRINT는 메모리의 주소를 나타내는 값이다.
*(ADDRINT*)ESP는 ESP를 또 다른 ADDRINT의 주소라고 보고 그 안에 들어있는 값을 바꾸는 것이므로 *(ADDRINT *)을 붙여주었다.
하지만 이 코드에는 문제가 있었다!
주소는 계속 바뀔 수 있다는 점이다.
그래서 printf 부분에서 스택에 들어있는 인자값을 바꾸는 방식으로 진행했다.
printf부분은 "__stdio_common_vfprintf" 가 불러질 때의 Routine이다.
그리고 이제 Hello World! 대신 다른 문자열을 출력해줄 것이다.
rdata위치에 Hello World! 문자열이 있는데, rdata의 주소가 계속 바뀐다는 점이 문제였다. 하지만, rdata에 들어있는 문자열간의 오프셋 차이는 일정할 것이므로 그 오프셋을 이용해서 Hello World! 대신 corrupted가 출력되게끔 코드를 짰다.
#include "pin.H" #include <iostream> namespace WINDOWS { #include <windows.h> } VOID change_esp(ADDRINT insAddr, CONTEXT *ctx, ADDRINT ESP) { *(ADDRINT*)(ESP + 16) = *(ADDRINT*)(ESP+16) + 98; } VOID ImageLoad(IMG img, VOID *v) { RTN print_rtn = RTN_FindByName(img, "__stdio_common_vfprintf"); if (RTN_Valid(print_rtn)) { RTN_Open(print_rtn); RTN_InsertCall(print_rtn, IPOINT_BEFORE, (AFUNPTR)change_esp, IARG_ADDRINT, "change_esp", IARG_CONTEXT, IARG_REG_VALUE, REG_ESP, IARG_END); RTN_Close(print_rtn); } } int main(INT32 argc, CHAR *argv[]) { PIN_InitSymbols(); if (PIN_Init(argc, argv)) return -1; IMG_AddInstrumentFunction(ImageLoad, 0); PIN_StartProgram(); return 0; }
'pintool' 카테고리의 다른 글
RDTSC (0) | 2018.10.17 |
---|---|
내장함수의 리턴값 바꾸기 (1) | 2018.10.17 |
Find executable img, section, code (0) | 2018.10.12 |
Disassemble (0) | 2018.10.12 |
Managed platforms support2 (0) | 2018.10.02 |