Be myself :: 'Analysis' 카테고리의 글 목록

달력

112024  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30


hypercomputer.tar.gz


PinTutorial.pdf

깔끔하게 보고 싶으신 분들은 위 pdf파일을 받아주시길..

제일 간단하게 프로그램의 Instruction을 추적하는 Pintool을 만들어 보겠다. Pintool을 만든다는 것은 Pin의 플러그인을 만든다는 느낌으로 만들면 된다. Pin은 JIT의 형태로 생각하면 된다. 자세한 것은 매뉴얼을 참고하자.

[1] instruction 추적하기

일단 타겟 프로그램을 다음과 같이 작성한다.

패스워드를 입력받고 0x31337이면 cong를 출력하는 프로그램이다. 다음과 같이 Main부분의 instruction만을 뽑아오도록 간단한 핀툴을 만든다.

#include <stdio.h>
#include <iostream>
#include "pin.H"
 
using namespace std;
 
#define START 0x4005FD
#define END 0x40065F
INT32 Usage()
{
         PIN_ERROR("this pintool print a trace of memory address\n");
         return -1;
}
 
void printip(void* ip)
{
         printf("address: %p\n",ip);
}
 
void Instruction(INS ins, VOID* v)
{
         long int a = (long int)INS_Address(ins);
         if(START<=a && a<=END)
         {
                 printf("Instruction \n");
                 INS_InsertCall(ins,IPOINT_BEFORE, (AFUNPTR)printip, IARG_INST_PTR, IARG_END);
         }
}
 
void Fini(INT32 code, VOID *v)
{
         cout << "Fini code: " << code << endl;
}
 
int main(int argc,char* argv[])
{
         if(PIN_Init(argc,argv))
                 return Usage();
 
         INS_AddInstrumentFunction(Instruction,0);
         PIN_AddFiniFunction(Fini,0);
 
         PIN_StartProgram();
         return 0;
}

}

코드에 대해 설명하자면 main에서 INS_AddInstrumentFunction 함수로 각 instruction이 실행될 때 실행되는 코드를 등록한다. Instruction함수를 보면 INS_Address로 각각 instruction이 실행될 때의 주소 값을 구해 main함수 내의 instruction의 주소 값만 뽑아온다. 또 각 instruction에 대해 INS_InsertCall을 이용해 instruction이 실행되기 전에 호출되는 callback 함수를 등록한다. 여기선 printip을 등록한다 printip에 넘어가는 인자는 IARG_INST_PTR이라는 인자가 넘어가는데 매뉴얼을 참고해 보면 이건 instruction의 주소 값이다.

다음과 같이 make.rules를 변경하고 make로 컴파일해서 돌려보자.

필자는 hyper.cpp이라는 이름으로 저 소스코드를 저장하였고 따라서 위와 같이 make 룰을 변경하였다. 그 다음 make를 통해 컴파일 하자.

그리고 다음과 같이 실행시키자.(root로 실행하여야 한다.)

이것과 ida로 본 instruction을 하나하나 비교해보자

위의 결과를 비교한 결과 내릴 수 있는 결론은 다음과 같다. 0x4005fd~400611까지 한 묶음, 0x40061B~0x400627까지 한 묶음, 0x400631~0x400639까지 한 묶음…[즉 BBL단위로 묶음] 이런 식으로 routine이 분기되기 전까지 Instruction함수가 호출되고 분기되고 난 후 INS_InsertCall() 으로 등록한 printip함수가 모조리 호출된다.

[2] 비밀번호 맞추기

위와 같이 instruction의 Opcode가 CMP이면 해당 오퍼렌드의 두번 째 비교 값을 가져와서 뿌려준다. 결과는 다음과 같다.

 

#include <stdio.h>
#include <iostream>
#include "pin.H"
 
using namespace std;
 
#define START 0x4005FD
#define END 0x40065F
INT32 Usage()
{
         PIN_ERROR("this pintool print a trace of memory address\n");
         return -1;
}
 
void Instruction(INS ins, VOID* v)
{
         long int a = (long int)INS_Address(ins);
         if(START<=a && a<=END)
         {
                 if(INS_Opcode(ins) == XED_ICLASS_CMP )
                 {
                          UINT64 value = INS_OperandImmediate(ins,1);
                          printf("value is 0x%lx \n",value);
                 }
                 
         }
}
 
void Fini(INT32 code, VOID *v)
{
         cout << "Fini code: " << code << endl;
}
 
int main(int argc,char* argv[])
{
         // Pin initiate
         if(PIN_Init(argc,argv))
                 return Usage();
 
         INS_AddInstrumentFunction(Instruction,0);
         PIN_AddFiniFunction(Fini,0);
 
         PIN_StartProgram();
         return 0;
}

 

[3] [2013 Plaid ctf] hypercomputer-1(bin 100)

문제 파일을 열어보면 다음과 같다.

hello함수에서 배너를 출력하고 CalcResult에서 원래 문자열을 조작해서 flag를 만들어 둔다. CalcResult나 다른 함수들을 리버싱 하면 알겠지만 쓸대없이 usleep과 많은 while문,for문을 만나게 된다. 따라서 핀툴로 이러한 루틴을 다 없애주면 flag를 줄것이다 J 아래의 코드는 그 조작을 한 핀툴을 작성한 것.

#include "pin.H"
#include <iostream>
#include <fstream>
#include <unistd.h>
 
int new_usleep(useconds_t usec)
{
         return 0;
}
 
void Image(IMG img, void *v)
{
         for(SYM sym = IMG_RegsymHead(img); SYM_Valid(sym); sym = SYM_Next(sym))
         {
                 string funcname = PIN_UndecorateSymbolName(SYM_Name(sym),UNDECORATION_NAME_ONLY);
                 if(funcname      == "usleep")
                 {
                          RTN rtn = RTN_FindByAddress(IMG_LowAddress(img)+SYM_Value(sym));
                          if(RTN_Valid(rtn))
                          {
                                   RTN_Open(rtn);
                                   RTN_Replace(rtn, (AFUNPTR) &new_usleep);
                                   RTN_Close(rtn);
                          }
                 }
         }
}
 
void xor_rax(CONTEXT *ctx)
{
         PIN_SetContextReg(ctx, REG_RAX,0);
}
 
void mov_rax_rdx(CONTEXT* ctx)
{
         ADDRINT rdx = PIN_GetContextReg(ctx, REG_RDX);
         PIN_SetContextReg(ctx, REG_RAX, rdx);
}
 
void delete_insns(BBL bbl)
{
         for(INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins))
         {
                 INS_Delete(ins);
         }
}
 
VOID Trace(TRACE trace, VOID *v)
{
    for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
        if(BBL_NumIns(bbl) == 2) {
            INS ins1 = BBL_InsHead(bbl);
            INS ins2 = INS_Next(ins1);
            if(INS_Disassemble(ins1) == "sub rax, 0x1" && INS_IsBranch(ins2) &&
                    INS_DirectBranchOrCallTargetAddress(ins2) == BBL_Address(bbl)) {
                BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR) &xor_rax,
                    IARG_CONTEXT, IARG_END);
                delete_insns(bbl);
            }
        }
        else if(BBL_NumIns(bbl) == 3) {
            INS ins1 = BBL_InsHead(bbl);
            INS ins2 = INS_Next(ins1);
            INS ins3 = INS_Next(ins2);
            if(INS_Disassemble(ins1) == "sub rax, 0x1" && INS_IsNop(ins2) &&
                    INS_DirectBranchOrCallTargetAddress(ins3) == BBL_Address(bbl)) {
                BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR) &xor_rax, IARG_CONTEXT,
                    IARG_END);
                delete_insns(bbl);
            }
            else if(INS_Disassemble(ins1) == "add rax, 0x1" &&
                    INS_Disassemble(ins2) == "cmp rax, rdx" &&
                    INS_DirectBranchOrCallTargetAddress(ins3) == BBL_Address(bbl)) {
                BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR) &mov_rax_rdx, 
                    IARG_CONTEXT,IARG_END);
                delete_insns(bbl);
            }
        }
    }
}
 
int main(int argc, char* argv[])
{
         if(PIN_Init(argc,argv))
         {
                 return 0;
         }
 
         PIN_InitSymbols();
 
         IMG_AddInstrumentFunction(Image,0);
         TRACE_AddInstrumentFunction(Trace,0);
 
         PIN_StartProgram();
         return 0;}

}

실행하면 다음과 같다.

이 문제의 설명은 다음의 원문에 잘 설명되어 있다: https://eindbazen.net/2013/04/pctf-2013-hypercomputer-1-bin-100/



'Analysis' 카테고리의 다른 글

Pin 기본 API살펴보기  (0) 2015.08.07
[smt solver]z3py 튜토리얼  (0) 2015.08.06
Pin tool 기본세팅  (1) 2015.07.17
Posted by flack3r
|

메뉴얼을 참고하면 처음 다음과 같은 말이 있다.


Conceptually, instrumentation consists of two components:

  • A mechanism that decides where and what code is inserted(instrumentation)

  • The code to execute at insertion points(analysis code)

즉 어디서 code 를 삽입할지 결정하는 메커니즘( 크게 4가지 메커니즘이 존재한다)과 그 code를 정의하는 부분이 필요하다.

위의 4가지 메커니즘을 보면 다음과 같다.

  • Trace Instrumentation: pintool processes one trace at a time by starting from the current instruction and ending with an unconditional branch (including calls and returns), which can be completed by using the TRACE_AddInstrumentFunction API call.
  • Instruction Instrumentation: pintool processes one instruction at a time, which can be completed by using the INS_AddInstrumentFunction API call.
  • Image Instrumentation: pintool processes an entire image where Pin can iterate over program sections, routines in a section or instructions in a routine. You can insert additional instructions before/after the routine is executed or before/after an instruction is executed. Here you have to use IMG_AddInstrumentFunction API call.
  • Routine Instrumentation: pintool processes one routine where Pin can iterate over instructions of a routine. Additional instructions can be inserted before/after routine execution or before/after instruction execution. Here you have to use RTN_AddInstrumentFunction API call.

  • There are a couple of callback functions that you can use with the pin framework and are presented below:

    • TRACE_AddInstrumentFunction: directly corresponds with the Trace Instrumentation Mode
    • INC_AddInstrumentFunction: directly corresponds with the Instruction Instrumentation Mode
    • IMG_AddInstrumentFunction: directly corresponds with the Image Instrumentation Mode
    • RTN_AddInstrumentFunction: directly corresponds with the Routine Instrumentation Mode
    • PIN_AddFiniFunction
    • PIN_AddDetachFunction
    (출처: http://resources.infosecinstitute.com/pin-dynamic-binary-instrumentation-framework/)

각각 부분을 간략히 설명하겠다.

1. TRACE부분은 BBL(Basic block: a single entrace, single exit sequence of instructions) 의 상위 개념인데 BBL은 간단하게 생각해서 어떤 분기문( if, goto ,call 등)에 의해 프로그램의 흐름이 바뀌었을 때 그 한 단락을 의미하고 TRACE는 처음 시작부분에서 끝날때 까지의 BBL 들의 연속된 리스트라고 생각하면 된다. 그림으로 보면 다음과 같다.





2. INS 같은 경우는 말 그대로 한 instruction에 대해 검사하는 것이다.


3. IMG 는 한 이미지가 로딩됬을때 호출되는 callback 함수로, 각종 라이브러리등이 로드될 때 호출된다.


4. RTN은 루틴단위로 호출된다.(하나의 함수단위로 호출된다고 생각하면 쉽다.)


따라서 위의 4개의 callback 함수로 어디서 code를 삽입할지 결정했다면, BBL_InsertCall이나 INS_InserCall, RTN_InsertCall 등으로 본인이 수행하고자 하는 코드를 등록하면 된다.

각각 예제가 궁금하신 분들은 메뉴얼 페이지에 잘 나와있으니 살펴보시라.

메뉴얼 페이지 : 메뉴얼

'Analysis' 카테고리의 다른 글

PinTool을 이용한 Instruction 추적하기, 간단한 ctf 풀이  (0) 2016.01.30
[smt solver]z3py 튜토리얼  (0) 2015.08.06
Pin tool 기본세팅  (1) 2015.07.17
Posted by flack3r
|

z3는 smt solver의 일종인데 간단하게 각종 수식들의 해답을 구해주는 일종의 공학계산기 역할이다. ㅋㅋ
소프트웨어 테스팅이나 생물학쪽, 역학 등등 여러분야에서 많이 쓰이는것 같다.

잘 정리된 문서는 다음과 같다: 튜토리얼 

일단 z3 설치는 https://github.com/Z3Prover/z3 여기 그대로 따라하면 됨
일단 간단한 연립방정식은 다음과 같이 풀린다

>>> from z3 import *

>>> x = Int('x')

>>> y = Int('y')

>>> solve(x+y>10,x>20)

[x = 21, y = -10]


변수를 실수범위 내에서 구하려면 다음과 같이 하면 됨.

>>> solve(x*y == 12,y==13)

[y = 13, x = 12/13]


또 그냥 solve메서드로 풀지 말고 Solver라는 객체를 생성해서 수식을 풀 수도 있다. 다음과 같이.

>>> x = Int('x')

>>> y = Int('y')

>>> s = Solver()

>>> s.add(x+y==3)

>>> s.add(y==2)

>>> s

[x + y == 3, y == 2]

>>> s.check()

sat

>>> s.model()

[y = 2, x = 1]


그리고 add 메서드로 로 수식 조건(constraints)를 추가하는데 잘못된 add를 막기 위해 약간의 스냅샷(?)기능이 존재한다 push() 와 pop()이다. 이를 이용하면 이전 상태로 돌아갈 수 있다.

>>> s

[x + y == 3, y == 2] >>> s.push()

>>> s.add(x<2)

>>> s.add(y**2>10)

>>> s

[x + y == 3, y == 2, x < 2, y**2 > 10]

>>> s.pop()

>>> s

[x + y == 3, y == 2]


마지막으로 함수기능을 설명하자면, 일단 간략한 정의는 다음과 같다.

Function('함수명', 입력값, 출력값)


>>> x = Int('x')

>>> y = Int('y')

>>> f = Function('f',IntSort(),IntSort())

>>> solve(f(f(x))==x,x+y==2)

[y = 0, x = 2, f = [2 -> 1, 1 -> 2, else -> 1]]

결과 값은 다음과 같이 해석하면 된다. 만약 y =0 이고 x =2 이고, f(x)의 상태는 다음과 같아야 한다. f(2) = 1, f(1) = 2, f(아무값) = 1 따라서, f(f(x))는 x가 2이므로 0이 성립( 합성함수 이므로) 하고 x+y ==2또한 성립한다.

'Analysis' 카테고리의 다른 글

PinTool을 이용한 Instruction 추적하기, 간단한 ctf 풀이  (0) 2016.01.30
Pin 기본 API살펴보기  (0) 2015.08.07
Pin tool 기본세팅  (1) 2015.07.17
Posted by flack3r
|

Pin tool 기본세팅

Analysis 2015. 7. 17. 00:11

일단 공식 홈페이지에서 .tar 을 받는다. 다운로드
pin 과 pin tool은 다르다. pin의 자세한 매커니즘은 잘 모르겠지만 intermediate representation(IR) 을 이용해서 각각의 인스트럭쳐가 해석된다. 이 때 각각 해석되는 변수들은 SSA-based(Static Single Assignment) 형태로 다뤄진다고 한다. SSA=based는 만약 a=3; a += 34; 라는 코드가 있다면 첫번째 a와 두번 째 a를 다르게 취급하는 형태 이다. 유사한 툴로는 Valgrind가 있다.

pin tool은 사용자가 공유라이브러리의 형태로 만들수 있고, pin에서 각각 인스트럭쳐를 fetch 하기 전, execute 한 후 , 라이브러리 로딩등의 상황에서 사용자가 원하는 행위들을 하도록 하게 해준다.
따라서 각각 상황에서 메모리 Status나 레지스터 값 등을 확인 할 수 있다.

이를 보안적 관점에서 바라보면, 만약 간단한 크랙미같은 것이 있다고 한다면, 각 if 문 전에 사용자 입력 값들이 어떻게 들어가는지 확인하고, 각각 값들을 심볼로 설정해 smt_solver 등과 함께 if문에 조건에 맞는 input값을 찾아내어 풀수있다. (이에 대한 것들은 구글링이나 http://shell-storm.org/blog/Taint-analysis-and-pattern-matching-with-Pin/ 여기를 참고하자) 더 발전해선 AEG(auto exploit generation) 등이나 제네릭한 퍼져도 만들 수 있을 것 같다.

아무튼, 일단 설치를 완료하면 pin을 컴파일 해야 할 것 같은데, 압푹을 풀면 바이너리가 있고 다양한 소스코드 예제들이 많다.. 메뉴얼과 튜토리얼 등을 참고해서 분석해 봐야겠다.

일단 pin 의 위치경로를 /etc/environment 에 설정하자. 그 다음 여기를 한번 보자.


다양한 소스들이 많다.. MyPinTool, ManualExamples... 등에 들어가서 makefile을 보면 makefile.rules을 인클루드 하고 있고 룰을 보면 다음과 같다 





컴파일 방법은 다음과 같다.

$ cd source/tools/ManualExamples
$ make obj-intel64/inscount0.so TARGET=intel64
$ cd source/tools/ManualExamples
$ make obj-ia32/inscount0.so TARGET=ia32

이 때 자기가 직접 만든 코드를 컴파일 하려고 하면 makefile.rules 에서 TEST_TOOL_ROOTS에 자기가 만든 파일명을 더 추가하고 위의 방법으로 컴파일 하면 된다. 실행은 다음과 같다.

$ ../../../pin -t obj-intel64/inscount0.so -- /bin/ls
Makefile          atrace.o     imageload.out  itrace      proccount
Makefile.example  imageload    inscount0      itrace.o    proccount.o
atrace            imageload.o  inscount0.o    itrace.out
$ cat inscount.out
Count 422838
$


핀 사이트 -> 사이트 가기 
핀 유저 가이드-> 유저 가이드

'Analysis' 카테고리의 다른 글

PinTool을 이용한 Instruction 추적하기, 간단한 ctf 풀이  (0) 2016.01.30
Pin 기본 API살펴보기  (0) 2015.08.07
[smt solver]z3py 튜토리얼  (0) 2015.08.06
Posted by flack3r
|