Reversing
- IDA Hexray 문자열이 제대로 보이지 않을때 옵션 설정방법 2018.09.20
- 암호학 정리(for CTF) 2018.04.05
- WinDBG 고급 명령어들 2017.06.07
- DBI - pin & pintool 2017.05.22 4
- DBI - Frida 를 이용한 DBI 2016.09.07 3
- Embedded 기기 리버싱 - 펌웨어 리버싱 2016.07.14 1
- Windbg 기본 - (3) 분석시 유용한 명령어들 2016.03.01 2
- WinDBG 심볼 간편 설정 2016.03.01
- Windows Kernel Reversing - Object 분석 2015.01.28
- 온라인 디컴파일러 - decompiler.fit.vutbr.cz 2014.10.31 3
- 비주얼 베이직 리버싱 팁 - vb decompiler To IDC(ida script) 2013.12.23 1
- .net 프로그램 리버싱 툴 2013.03.03 1
- Windbg 기본 - (2) 기본 명령어들-2 2012.08.08
- Windbg 기본 - (1) 기본 명령어들 2012.08.07
IDA Hexray 문자열이 제대로 보이지 않을때 옵션 설정방법
IDA Hexray
간혹 헥스레이에서 문자열이 "test1234" 대신 atest 요런 식으로 변수명으로 나와서 불편할 때가 있다.
이런 경우 설정방법.
요렇게 문자열 대신 변수명으로 나올때
헥스레이 옵션에서 "Print only constant string literals" 옵션 체크 해제
이제 잘 보인다.
'Reversing' 카테고리의 다른 글
암호학 정리(for CTF) (0) | 2018.04.05 |
---|---|
WinDBG 고급 명령어들 (0) | 2017.06.07 |
DBI - pin & pintool (4) | 2017.05.22 |
DBI - Frida 를 이용한 DBI (3) | 2016.09.07 |
Embedded 기기 리버싱 - 펌웨어 리버싱 (1) | 2016.07.14 |
암호학 정리(for CTF)
2. 점검툴
'Reversing' 카테고리의 다른 글
IDA Hexray 문자열이 제대로 보이지 않을때 옵션 설정방법 (0) | 2018.09.20 |
---|---|
WinDBG 고급 명령어들 (0) | 2017.06.07 |
DBI - pin & pintool (4) | 2017.05.22 |
DBI - Frida 를 이용한 DBI (3) | 2016.09.07 |
Embedded 기기 리버싱 - 펌웨어 리버싱 (1) | 2016.07.14 |
WinDBG 고급 명령어들
WinDBG 고급 분석을 위한 명령어들 간단 정리
# 설정 미리 해놓기(배치파일)
- windbg.bat
"C:\Program Files\Windows Kits\10\Debuggers\x86\windbg.exe" -c".symfix+;.load c:\\blwdbgue.dll;g" "c:\program files\internet explorer\iexplore.exe"
# syntax color highlight
- blwdbgue 다운로드 및 .load 로 로드
# 심볼 설정 쉽게 하기
0:009> .symfix+
# 심볼 확인
0:009> x jscript9!JS::JavascriptArray::*
6548df1c jscript9!Js::JavascriptArray::IsEnumerable (<no parameter info>)
6534cdfb jscript9!Js::JavascriptArray::GetFromIndex (<no parameter info>)
6548fa51 jscript9!Js::JavascriptArray::BigIndex::BigIndex (<no parameter info>)
6548deb2 jscript9!Js::JavascriptArray::SetEnumerable (<no parameter info>)
653ba673 jscript9!Js::JavascriptArray::EntrySome (<no parameter info>)
65327b86 jscript9!Js::JavascriptArray::HasItem (<no parameter info>)
652a2f78 jscript9!Js::JavascriptArray::`vftable' = <no type information>
6548f898 jscript9!Js::JavascriptArray::BigIndex::SetItem (<no parameter info>)
6548dff8 jscript9!Js::JavascriptArray::IsDirectAccessArray (<no parameter info>)
6534be75 jscript9!Js::JavascriptArray::Sort (<no parameter info>)
65531508 jscript9!Js::JavascriptArray::EntryInfo::Map = <no type information>
653a6b3e jscript9!Js::JavascriptArray::EntryIsArray (<no parameter info>)
0:009> x jscript9!JS::JavascriptArray::Get*
0:009> x jscript9!JS::JavascriptArray::Set*
# 하드웨어 bp (access)
- ba w4 0x1f1f0000
# 주소 정보 출력
- 0:009> x jscript9!JS::JavascriptArray::*
# 힙 정보 확인(page heap, stack trace 설정해야 자세히 보임)
- !heap -p -a 0x254a0a12
# 로드된 모듈 정보 출력
0:009> lm
start end module name
013a0000 0145c000 iexplore (deferred)
04780000 048ac000 Cooxie (deferred)
05a80000 05a9e000 iToolsBHO (deferred)
63b90000 63d53000 d3d9 (deferred)
63ec0000 65297000 Flash32_25_0_0_171 (deferred)
652a0000 65562000 jscript9 (pdb symbols) C:\Program Files\Windows Kits\10\Debuggers\x86\sym\jscript9.pdb\6E55E6B5AC4B4699BFCF4B58510435202\jscript9.pdb
65570000 656a6000 DWrite (deferred)
656b0000 659f7000 d2d1 (deferred)
65f00000 66cbd000 MSHTML (pdb symbols) C:\Program Files\Windows Kits\10\Debuggers\x86\sym\mshtml.pdb\98191859560C471FB6BA0B1D33DAACCB2\mshtml.pdb
66cc0000 679e9000 IEFRAME (pdb symbols) C:\Program Files\Window
'Reversing' 카테고리의 다른 글
IDA Hexray 문자열이 제대로 보이지 않을때 옵션 설정방법 (0) | 2018.09.20 |
---|---|
암호학 정리(for CTF) (0) | 2018.04.05 |
DBI - pin & pintool (4) | 2017.05.22 |
DBI - Frida 를 이용한 DBI (3) | 2016.09.07 |
Embedded 기기 리버싱 - 펌웨어 리버싱 (1) | 2016.07.14 |
DBI - pin & pintool
PIN 에 대해서 공부한지는 조금 되었으나 적당히 기존 코드로만 붙여넣기 해서 사용했던 것이 사실이다. 최근 개인 프로젝트로 PIN 을 사용할 일이 생겨서 하는 김에 정리해 둔다.
PIN
PIN 이란, Intel 에서 제작 및 관리중인 Dynamic Binary Instrumentation Framework 이다. BI 분야에서 실행을 하지 않고 조사하는 SBI 와 동적으로 실행중 코드를 조사하는 DBI 가 있는데, 그 중 PIN 은 DBI 를 위한 SDK(?) 정도로 볼 수 있다.
Intel 이란 기업에서 관리하기 때문에 상당히 업데이트가 잘 되고 있으며 매뉴얼도 매우 충실하게 잘 되어 있다. 또한 수많은 예제코드가 들어 있어서 몇개의 코드만 분석해 보면 바로 사용방법을 알 수 있을 정도로 완성도가 높다.
한가지 단점은 C++ 로 작성해서 DLL 로 컴파일 해야 하므로 스크립트 언어에 비해 수정&적용이 조금 오래 걸린다는 점이 있다. 하지만 이러한 단점은 장점에 비해 크지 않으므로 수년전부터 현재까지도 PIN 은 매우 인기 있는 DBI 프레임워크로 자리잡았다.
PIN 은 그 자체로 pin.exe 로 독립된 바이너리이며, 실행 파일을 에뮬레이션 해준다. 에뮬레이션 하는 동안 PINTOOL 로 작성한 DLL 코드를 통해 다양하게 동적으로 코드를 수행할 수 있다.
PINTOOL
PINTOOL 은 PIN SDK 를 이용하여 개발한 라이브러리이다. pin.exe 실행 시 옵션으로(-t) 지정해주면 해당 PINTOOL 을 이용하여 타겟 바이너리를 실행시켜 준다.
Build PINTOOL
다운로드 및 설치는 검색하면 많으니 타 자료를 참고바란다. 여러가지 방법이 있지만 개인적으로는 cygwin + make 가 편한 듯 하다. visual studio 로도 가능하지만 컴파일 프로그램 특성상 소스코드 수정, 컴파일 및 실행, 빌드된 파일 이동, 실행 등을 자주 해야 해서 차라리 make 로 배치 파일을 만드는 것이 편하다.
# make.bat
cd C:\Users\hyunmini\Desktop\pin-3.2-81205-msvc-windows\source\tools\MyPinTool
make
copy /y obj-ia32\MyPinTool.dll c:\Users\FSI\Desktop\dbi\pin
cd c:\Users\hyunmini\Desktop\dbi\pin
Simple Example 1 - call tracer
#include "pin.H" #include <asm/unistd.h> #include <iostream> #include <fstream> #include <list> UINT32 insCount = 0; UINT32 bblCount = 0; UINT32 threadCount = 0; UINT32 traceCount = 0; std::ostream * out = &cerr; KNOB<string> KnobTraceString(KNOB_MODE_WRITEONCE, "pintool", "s", "", "trace string"); INT32 Usage() { cerr << "This tool prints out the traced call with arguments." << endl; cerr << KNOB_BASE::StringKnobSummary() << endl; return -1; } string invalid = "invalid_rtn"; const string *Target2String(ADDRINT target) { string name = RTN_FindNameByAddress(target); if (name == "") { return &invalid; } else if (name == ".text" || name == "unnamedImageEntryPoint") { return new string(StringFromAddrint(target)); } else return new string(name); } string ReadCString(ADDRINT target){ ADDRINT Buffer; PIN_SafeCopy(&Buffer, (ADDRINT *)(target), sizeof(ADDRINT)); string cstring; while (1) { char c = 0; if (PIN_SafeCopy(&c, (ADDRINT *) Buffer, 1) != 1) break; if (c == 0) break; cstring += c; Buffer += 1; } return cstring; } VOID do_call_args(ADDRINT ins,const string *s, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT esp) { PIN_LockClient(); string img_name = IMG_Name(IMG_FindByAddress(ins)); PIN_UnlockClient(); string base_img_name = img_name.substr(img_name.find_last_of("/\\") + 1); string argstr1 = ReadCString(esp); string argstr2 = ReadCString(esp+4); string argstr3 = ReadCString(esp+8); if( argstr1.find(KnobTraceString.Value()) != string::npos || argstr2.find(KnobTraceString.Value()) != string::npos || argstr3.find(KnobTraceString.Value()) != string::npos ){ *out << StringFromAddrint(ins) << " : " << base_img_name << "!" << *s << "(0x" << std::hex << arg0 << ", 0x" << arg1 << ", 0x" << arg2 << "...)" << endl; if(argstr1.length()>10){ argstr1 = argstr1.substr(0,10); argstr1 += "..."; } if(argstr2.length()>10){ argstr2 = argstr2.substr(0,10); argstr2 += "..."; } if(argstr3.length()>10){ argstr3 = argstr3.substr(0,10); argstr3 += "..."; } *out << " arg1 : " << argstr1 << endl; *out << " arg2 : " << argstr2 << endl; *out << " arg3 : " << argstr3 << endl; } } VOID do_call_args_indirect(ADDRINT ins, ADDRINT target, BOOL taken, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT esp) { if( !taken ) return; const string *s = Target2String(target); do_call_args(ins, s, arg0, arg1, arg2, esp); if (s != &invalid) delete s; } /* ===================================================================== */ VOID Trace(TRACE trace, VOID *v) { PIN_LockClient(); IMG img = IMG_FindByAddress(TRACE_Address(trace)); PIN_UnlockClient(); if (IMG_Valid(img) && IMG_IsMainExecutable(img)){ for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) { INS tail = BBL_InsTail(bbl); if( INS_IsCall(tail) ) { if( INS_IsDirectBranchOrCall(tail) ) { // direct call const ADDRINT target = INS_DirectBranchOrCallTargetAddress(tail); INS_InsertPredicatedCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args), IARG_INST_PTR, IARG_PTR, Target2String(target), IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_REG_VALUE, REG_ESP, IARG_END); } else { // indirect call INS_InsertCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect), IARG_INST_PTR, IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_REG_VALUE, REG_ESP, IARG_END); } } else { RTN rtn = TRACE_Rtn(trace); if( RTN_Valid(rtn) && !INS_IsDirectBranchOrCall(tail)) { INS_InsertCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect), IARG_INST_PTR, IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_REG_VALUE, REG_ESP, IARG_END); } } } } } int main(int argc, char *argv[]) { PIN_InitSymbols(); if( PIN_Init(argc,argv) ){ return Usage(); } string fileName = "trace_result.txt"; if (!fileName.empty()) { out = new std::ofstream(fileName.c_str());} TRACE_AddInstrumentFunction(Trace, 0); PIN_StartProgram(); return 0; }
실행결과
x00489d99 : VUPlayer.exe!_mbscmp(0x3c34f3c, 0x3be35f8, 0x74aeac8...) arg1 : AAAAAAAAAA... arg2 : #VUPlayer ... arg3 : 0x004552ac : VUPlayer.exe!_mbsicmp(0x3c3408c, 0x51f140, 0x0...) arg1 : AAAAAAAAAA... arg2 : mod arg3 : 0x004552d2 : VUPlayer.exe!_mbsicmp(0x3c3408c, 0x51f13c, 0x0...) arg1 : AAAAAAAAAA... arg2 : s3m arg3 : 0x004552f8 : VUPlayer.exe!_mbsicmp(0x3c3408c, 0x51f138, 0x0...) arg1 : AAAAAAAAAA... arg2 : xm arg3 : 0x00456191 : VUPlayer.exe!fopen(0x3c3408c, 0x51e098, 0x12d198...) arg1 : AAAAAAAAAA... arg2 : rb arg3 : dœP 0x004562a3 : VUPlayer.exe!0x004b9f68(0x0, 0x3c3408c, 0x0...) arg1 : arg2 : AAAAAAAAAA... arg3 : 0x004b9f68 : VUPlayer.exe!BASS_MusicLoad(0x4562a8, 0x0, 0x3c3408c...) arg1 : ‰Eüƒ}ü arg2 : arg3 : AAAAAAAAAA... 0x00456191 : VUPlayer.exe!fopen(0x3c3408c, 0x51e098, 0x12d198...) arg1 : AAAAAAAAAA... arg2 : rb arg3 : dœP 0x00456191 : VUPlayer.exe!fopen(0x3c3408c, 0x51e098, 0x12d198...) arg1 : AAAAAAAAAA... arg2 : rb arg3 : dœP 0x00453313 : VUPlayer.exe!lstrcpyA(0x12cc44, 0x3c3408c, 0x12d3a8...) arg1 : arg2 : AAAAAAAAAA... arg3 : 0ü¿4P 0x00453325 : VUPlayer.exe!fopen(0x12cc44, 0x51e098, 0x12d3a8...) arg1 : AAAAAAAAAA... arg2 : rb arg3 : AAAAAAAAAA...
Taint Analysis with PIN
taint analysis 는 이론부터 설명하면 매우 길기 때문에 더이상의 설명은 생략한다!(...)
결론은 쓸만하지만 오류 없이 쓰려면 훨~씬 세세한 컨트롤을 해줘야 함. 그러므로 여기까지만..
* 코드 일부 생략.
** (http://shell-storm.org/blog/Taint-analysis-and-pattern-matching-with-Pin 코드를 아주 많이 참고 하였음을 밝힙니다)
#include "pin.H"
#include <asm/unistd.h> #include <iostream> #include <fstream> #include <list> UINT32 insCount = 0; UINT32 bblCount = 0; UINT32 threadCount = 0; UINT32 traceCount = 0; BOOL start_taint = false; std::ostream * out = &cerr; std::list<ADDRINT> addressTainted; std::list<REG> regsTainted; string invalid = "invalid_rtn"; //////////////////////// // trace user input // //////////////////////// VOID fgetsBefore(ADDRINT arg0, ADDRINT arg1, ADDRINT arg2) { *out << "[Taint] fgets() : " << endl; *out << " buf : 0x" << std::hex << arg1 << endl; *out << " size : 0x" << arg2 << endl; int size = static_cast<ADDRINT>(arg2); start_taint = true; for (int i=0;i<size;i++){ addressTainted.push_back(arg1+i); } } VOID recvBefore(ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT arg3) { *out << "[Taint] recv() : " << endl; *out << " buf : 0x" << std::hex << arg2 << endl; *out << " size : 0x" << arg3 << endl; int size = static_cast<ADDRINT>(arg3); start_taint = true; for (int i=0;i<size;i++){ addressTainted.push_back(arg2+i); } } /////////////////////// /// taint analysis /// /////////////////////// bool IsRegTainted(REG reg){ list<REG>::iterator i; for(i = regsTainted.begin(); i != regsTainted.end(); i++){ if (*i == reg){ return true; } } return false; } bool IsMemTainted(ADDRINT mem){ list<ADDRINT>::iterator i; for(i = addressTainted.begin(); i != addressTainted.end(); i++){ if (mem == *i){ return true; } } return false; } bool removeRegTainted(REG reg){ switch(reg){ case REG_EAX: regsTainted.remove(REG_EAX); case REG_AX: regsTainted.remove(REG_AX); case REG_AH: regsTainted.remove(REG_AH); case REG_AL: regsTainted.remove(REG_AL); break; case REG_EBX: regsTainted.remove(REG_EBX); case REG_BX: regsTainted.remove(REG_BX); case REG_BH: regsTainted.remove(REG_BH); case REG_BL: regsTainted.remove(REG_BL); break; case REG_ECX: regsTainted.remove(REG_ECX); case REG_CX: regsTainted.remove(REG_CX); case REG_CH: regsTainted.remove(REG_CH); case REG_CL: regsTainted.remove(REG_CL); break; case REG_EDX: regsTainted.remove(REG_EDX); case REG_DX: regsTainted.remove(REG_DX); case REG_DH: regsTainted.remove(REG_DH); case REG_DL: regsTainted.remove(REG_DL); break; case REG_EDI: regsTainted.remove(REG_EDI); case REG_DI: regsTainted.remove(REG_DI); break; case REG_ESI: regsTainted.remove(REG_ESI); case REG_SI: regsTainted.remove(REG_SI); break; default: return false; } *out << "\t\t\t" << REG_StringShort(reg) << " is now freed" << std::endl; return true; } bool taintReg(REG reg){ if (IsRegTainted(reg)){ * out << "\t\t\t" << REG_StringShort(reg) << " is already tainted" << std::endl; return false; } switch(reg){ case REG_EAX: regsTainted.push_front(REG_EAX); case REG_AX: regsTainted.push_front(REG_AX); case REG_AH: regsTainted.push_front(REG_AH); case REG_AL: regsTainted.push_front(REG_AL); break; case REG_EBX: regsTainted.push_front(REG_EBX); case REG_BX: regsTainted.push_front(REG_BX); case REG_BH: regsTainted.push_front(REG_BH); case REG_BL: regsTainted.push_front(REG_BL); break; case REG_ECX: regsTainted.push_front(REG_ECX); case REG_CX: regsTainted.push_front(REG_CX); case REG_CH: regsTainted.push_front(REG_CH); case REG_CL: regsTainted.push_front(REG_CL); break; case REG_EDX: regsTainted.push_front(REG_EDX); case REG_DX: regsTainted.push_front(REG_DX); case REG_DH: regsTainted.push_front(REG_DH); case REG_DL: regsTainted.push_front(REG_DL); break; case REG_EDI: regsTainted.push_front(REG_EDI); case REG_DI: regsTainted.push_front(REG_DI); break; case REG_ESI: regsTainted.push_front(REG_ESI); case REG_SI: regsTainted.push_front(REG_SI); break; default: *out << "\t\t\t" << REG_StringShort(reg) << " can't be tainted" << std::endl; return false; } *out << "\t\t\t" << REG_StringShort(reg) << " is now tainted" << std::endl; return true; } VOID ReadMem(INS ins, ADDRINT memOp){ // memory -> reg list<ADDRINT>::iterator i; ADDRINT addr = memOp; REG read_reg; if (INS_OperandCount(ins) != 2) return; read_reg = INS_OperandReg(ins, 0); for(i = addressTainted.begin(); i != addressTainted.end(); i++){ if (addr == *i){ // tainted memory > register *out << "[Read][0x" << std::hex << INS_Address(ins) <<"] : " << INS_Disassemble(ins) << endl; taintReg(read_reg); return ; } } if (IsRegTainted(read_reg)){ // untainted memory > tainted register => clear reg *out << "[Read][0x" << std::hex << INS_Address(ins) <<"] : " << INS_Disassemble(ins) << endl; removeRegTainted(read_reg); } } VOID WriteMem(INS ins, ADDRINT memOp){ // reg -> memory list<ADDRINT>::iterator i; ADDRINT addr = memOp; REG read_reg; if (INS_OperandCount(ins) != 2) return; read_reg = INS_OperandReg(ins, 1); for(i = addressTainted.begin(); i != addressTainted.end(); i++){ if (addr == *i){ // tainted memory *out << "[Write][0x" << std::hex << INS_Address(ins) <<"] : " << INS_Disassemble(ins) << endl; if (!REG_valid(read_reg) || !IsRegTainted(read_reg)){ // untainted register > tainted memory => clear memory addressTainted.remove(addr); } *out << std::hex << "\t\t\t0x" << addr << " is now freed" << std::endl; return; } } if (IsRegTainted(read_reg)) { // tainted reg > untainted memory => tainted addressTainted.push_back(addr); *out << std::hex << "\t\t\t0x" << addr << " is now tainted" << std::endl; return; } } VOID spreadReg(INS ins) { REG reg_r, reg_w; if (INS_OperandCount(ins) != 2) return; reg_r = INS_RegR(ins, 0); // src reg_w = INS_RegW(ins, 0); // dest if (REG_valid(reg_w)){ // reg_w not const(address) if (IsRegTainted(reg_w) && (!REG_valid(reg_r) || !IsRegTainted(reg_r))){ // untainted reg > tainted reg => clear reg *out << "[SPREAD]\t\t" << INS_Address(ins) << ": " << INS_Disassemble(ins) << std::endl; *out << "\t\t\toutput: "<< REG_StringShort(reg_w) << " | input: " << (REG_valid(reg_r) ? REG_StringShort(reg_r) : "constant") << std::endl; removeRegTainted(reg_w); } else if (!IsRegTainted(reg_w) && IsRegTainted(reg_r)){ // tainted reg > untainted reg => tainted *out << "[SPREAD]\t\t" << INS_Address(ins) << ": " << INS_Disassemble(ins) << std::endl; *out << "\t\t\toutput: " << REG_StringShort(reg_w) << " | input: "<< REG_StringShort(reg_r) << std::endl; taintReg(reg_w); } } } VOID Instruction(INS ins, VOID *v){ if (IMG_IsMainExecutable(IMG_FindByAddress(INS_Address(ins)))){ // callback for read instruction // memory -> reg if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsRead(ins, 0) && INS_OperandIsReg(ins, 0)){ if (start_taint){ INS_InsertCall( ins, IPOINT_BEFORE, (AFUNPTR)ReadMem, IARG_PTR, ins, IARG_MEMORYOP_EA, 0, IARG_END); } } // callback for write instruction // reg -> memory else if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsWritten(ins, 0)){ if (start_taint){ INS_InsertCall( ins, IPOINT_BEFORE, (AFUNPTR)WriteMem, IARG_PTR, ins, IARG_MEMORYOP_EA, 0, IARG_END); } } // callback for spread instruction // reg -> reg else if (INS_OperandCount(ins) > 1 && INS_OperandIsReg(ins, 0)){ if (start_taint){ //*out << "[Spread][0x" << std::hex << INS_Address(ins) <<"] : " << INS_Disassemble(ins) << endl; INS_InsertCall( ins, IPOINT_BEFORE, (AFUNPTR)spreadReg, IARG_PTR, ins, IARG_END); } } } } VOID Image(IMG img, VOID *v){ // fgets(&Buf, 2000, File); RTN fgetsRtn = RTN_FindByName(img, "fgets"); if (RTN_Valid(fgetsRtn)) { RTN_Open(fgetsRtn); RTN_InsertCall(fgetsRtn, IPOINT_BEFORE, (AFUNPTR)fgetsBefore, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_END); RTN_Close(fgetsRtn); } // recv(sock, &buf, 2000, 0); RTN recvRtn = RTN_FindByName(img, "recv"); if (RTN_Valid(recvRtn)) { RTN_Open(recvRtn); RTN_InsertCall(recvRtn, IPOINT_BEFORE, (AFUNPTR)recvBefore, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_FUNCARG_CALLSITE_VALUE, 3, IARG_END); RTN_Close(recvRtn); } } VOID Fini(INT32 code, VOID *v){ /* list<ADDRINT>::iterator li; for(li=addressTainted.begin(); li!=addressTainted.end(); li++){ * out << std::hex << *li << endl; } */ *out << "[+] Finish!!" << endl; } ///////////////////////////// ////// call trace ///////// ///////////////////////////// const string *Target2String(ADDRINT target) { string name = RTN_FindNameByAddress(target); if (name == "") { return &invalid; } else if (name == ".text" || name == "unnamedImageEntryPoint") { return new string(StringFromAddrint(target)); } else return new string(name); } string ReadCString(ADDRINT target){ ADDRINT Buffer; PIN_SafeCopy(&Buffer, (ADDRINT *)(target), sizeof(ADDRINT)); string cstring; while (1) { char c = 0; if (PIN_SafeCopy(&c, (ADDRINT *) Buffer, 1) != 1) break; if (c == 0) break; cstring += c; Buffer += 1; } return cstring; } VOID do_call_args(ADDRINT ins,const string *s, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT esp) { PIN_LockClient(); string img_name = IMG_Name(IMG_FindByAddress(ins)); PIN_UnlockClient(); string base_img_name = img_name.substr(img_name.find_last_of("/\\") + 1); string argstr1 = ReadCString(esp); string argstr2 = ReadCString(esp+4); string argstr3 = ReadCString(esp+8); bool tainted_func = false; if ( IsMemTainted(arg0) ) { tainted_func = true; } if ( IsMemTainted(arg1) ) { tainted_func = true; } if ( IsMemTainted(arg2) ) { tainted_func = true; } if ( tainted_func ) { *out << "[tainted arg]" << StringFromAddrint(ins) << " : " << base_img_name << "!" << *s << "(0x" << std::hex << arg0 << ", 0x" << arg1 << ", 0x" << arg2 << "...)" << endl; if (argstr1.length()>10){ argstr1 = argstr1.substr(0,10); argstr1 += "..."; } if (argstr2.length()>10){ argstr2 = argstr2.substr(0,10); argstr2 += "..."; } if (argstr3.length()>10){ argstr3 = argstr3.substr(0,10); argstr3 += "..."; } *out << " arg1 : " << argstr1 << endl; *out << " arg2 : " << argstr2 << endl; *out << " arg3 : " << argstr3 << endl; } } VOID do_call_args_indirect(ADDRINT ins, ADDRINT target, BOOL taken, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT esp) { if ( !taken ) return; const string *s = Target2String(target); do_call_args(ins, s, arg0, arg1, arg2, esp); if (s != &invalid) delete s; } /* ===================================================================== */ VOID Trace(TRACE trace, VOID *v) { PIN_LockClient(); IMG img = IMG_FindByAddress(TRACE_Address(trace)); PIN_UnlockClient(); // if (IMG_Valid(img) && IMG_IsMainExecutable(img)){ if (IMG_Valid(img) && IMG_IsMainExecutable(img)){ for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) { INS tail = BBL_InsTail(bbl); if ( INS_IsCall(tail) ) { if ( INS_IsDirectBranchOrCall(tail) ) { // direct call const ADDRINT target = INS_DirectBranchOrCallTargetAddress(tail); INS_InsertPredicatedCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args), IARG_INST_PTR, IARG_PTR, Target2String(target), IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_REG_VALUE, REG_ESP, IARG_END); } else { // indirect call INS_InsertCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect), IARG_INST_PTR, IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_REG_VALUE, REG_ESP, IARG_END); } } else { RTN rtn = TRACE_Rtn(trace); if ( RTN_Valid(rtn) && !INS_IsDirectBranchOrCall(tail)) { INS_InsertCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect), IARG_INST_PTR, IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_FUNCARG_CALLSITE_VALUE, 1, IARG_FUNCARG_CALLSITE_VALUE, 2, IARG_REG_VALUE, REG_ESP, IARG_END); } } } } } ///////////////////////////////////////////////// ////////////// call trace end /////////////////// ///////////////////////////////////////////////// int main(int argc, char *argv[]){ PIN_InitSymbols(); if ( PIN_Init(argc,argv) ){ return -1; } string fileName = "taint_analysis_result.txt"; if (!fileName.empty()) { out = new std::ofstream(fileName.c_str());} IMG_AddInstrumentFunction(Image, 0); INS_AddInstrumentFunction(Instruction, 0); TRACE_AddInstrumentFunction(Trace, 0); PIN_AddFiniFunction(Fini, 0); PIN_StartProgram(); return 0; }
실행결과
[Taint] fgets() : buf : 0x12f76c size : 0x7d0 [tainted arg]0x0040113e : reader_taint.exe!myreadfile(0x12f76c, 0x61616161, 0x61616161...) arg1 : aaaaaaaaaa... arg2 : arg3 : [Read][0x401029] : mov dl, byte ptr [ecx+0x5] dl is now tainted 0x12f55f is now tainted [Read][0x401035] : mov cl, byte ptr [eax+0x6] cl is now tainted 0x12f55d is now tainted [Read][0x401041] : mov al, byte ptr [edx+0x8] al is now tainted 0x12f55e is now tainted [Write][0x40104d] : mov byte ptr [ecx+0x2], 0x66 0x12f76e is now freed [Write][0x401054] : mov byte ptr [edx+0x4], 0x67 0x12f770 is now freed [Write][0x40105b] : mov byte ptr [eax+0xb], 0x68 0x12f777 is now freed [Write][0x401062] : mov byte ptr [ecx+0x15], 0x6d 0x12f781 is now freed [tainted arg]0x00401071 : reader_taint.exe!strcpy(0x12f560, 0x12f76c, 0x61616101...) arg1 : arg2 : aafagaaaaa... arg3 : [tainted arg]0x004010a0 : reader_taint.exe!main(0x401143, 0x12f76c, 0x61666161...) arg1 : ƒÄëë3À‹... arg2 : aafagaaaaa... arg3 : [+] Finish!!
'Reversing' 카테고리의 다른 글
암호학 정리(for CTF) (0) | 2018.04.05 |
---|---|
WinDBG 고급 명령어들 (0) | 2017.06.07 |
DBI - Frida 를 이용한 DBI (3) | 2016.09.07 |
Embedded 기기 리버싱 - 펌웨어 리버싱 (1) | 2016.07.14 |
Windbg 기본 - (3) 분석시 유용한 명령어들 (2) | 2016.03.01 |
DBI - Frida 를 이용한 DBI
DBI
Dynamic Binary Instrumentation - 동적 바이너리 조사
printf("test %s", buf); 등과 같이 특정 시점에서의 변수값 등을 확인하거나 프로그램의 행위를 조사하는 일을 Instrumentation 라고 부른다. 소스 코드 수준에서 하는 행위를 SI (Source Instrumentation), 바이너리 수준에서 하는 행위를 BI 라 한다. BI 중에서도 바이너리 실행중에 조사하는 것을 DBI 라 부른다. 조금 더 구체적으로 설명하면, 바이너리가 어떤 함수들을 호출하는지, 또 인자값은 무엇인지 등을 조사하는 것이라 보면 될 것 같다. 예를 들어, 악성코드 분석을 할때 각종 모니터링 툴들을 켜고 악성코드를 실행하여 행위를 분석하는 것 또한 동적 바이너리 조사의 일종이라고 볼 수 있다.
DBI 구현
DBI 를 구현하는 방법에는 디버거 스크립트를 이용하는 방법, 후킹을 이용하는 방법, 코드 캐쉬와 CPU 가상화를 이용한 에뮬레이팅 등이 있다. 먼저 디버거를 이용하는 경우에는 디버거 스크립트와 조건부 브레이크포인트, 로그기능 등을 이용할 수 있다. 후킹을 이용하는 경우 주요 함수들( 네트워크 관련 함수들, File I/O 함수들, 문자열 처리 함수 등)에 후킹을 설정한 뒤 함수 후킹 시 인자값 등을 기록하거나 변조하는 행위들을 할 수 있다. 마지막으로 에뮬레이팅을 이용한 방법은 코드를 읽어서 가상 CPU 로 실행시키는 방법이다. 이전의 두가지 방법과는 다르게 투명성이 보장된다. 디버거, 후킹의 경우 이미 많이 알려져 있고 프로세스의 코드를 직접 변경하기 때문에 보호기법에 의해 쉽게 발견될 수 있다. 하지만 에뮬레이팅의 경우 코드를 복사해서 해석한뒤 실행하므로 일반적인 탐지기법들을 우회할 수 있다.
DBI 로 할 수 있는 것들
- Flow Analysis
- Reversing Automation
- Malware Analysis
- Taint Analysis
- Binary Visualization (ex: VERA)
- Vulnerability(Exploit) Analysis
이외에도 기타 상상할 수 있는 다양한 자동 분석들이 가능하다. DBI 를 이용해서 안티디버깅 코드를 탐지하는 논문도 보았고, unpacking automation 논문도 본 적이 있다. 최근에는 DBI 를 Tracer 로 사용해서 로그를 남기고 그 정보들을 활용하여 Symbolic Execution, SMT Solver 등과 연계하여 취약점을 자동으로 찾거나(AEG, Automatic Exploit Generation) CTF 문제 등을 자동으로 풀어주는 등 Advanced 한 주제들도 지속적으로 연구되고 있다. 관심이 있다면 Triton, Angr 등의 Framework 를 살펴보면 된다.
DBI Framework
PIN & PINTOOL
intel 에서 관리하는 DBI 프레임워크로 기업이 관리하는 특성상 유지보수가 매우 잘 되고 있으며 다양한 플랫폼을 지원한다. 단점은 Intel 아키텍쳐(intel cpu)만 지원한다는 점과 C++ 로 작성해야 해서 매번 컴파일 하는 것이 조금 번거롭다는 것이다. 코드를 해석해서 가상 CPU 에서 실행시킨다. 실제로 원본 파일은 실행조차 되지 않는다. 때문에 투명성이 보장되지만 속도 이슈가 있다.
(참고) http://hyunmini.tistory.com/87
FRIDA
FRIDA 는 scriptable 한 DBI 프레임워크로, http://www.frida.re 에서 무료로 다운로드 및 설치가 가능하다.(심지어 오픈소스이다. 근데 vala 라는 특이한 프로그래밍 언어로 작성되어 있다. 신기함...) FRIDA 는 기타 DBI 프레임워크와 약간 다른 구조를 가지고 있는데, DBI 를 위한 주 조작은 자바스크립트를 통해서 하며, C/S 구조로 동작하게 된다. 즉 처음에 바이너리에 프레임워크 라이브러리를 인젝션하여 파이프를 만들어 놓고, 그 파이프를 통해서 명령을 주고 받으면서 바이너리 조사를 할 수 있도록 되어 있다. 물론 C/S 를 사용하지 않고 그냥 PIN 처럼 내부적으로 동작하도록 할 수도 있다. 여러가지 언어를 이용하여 스크립트를 작성할 수 있으나(바이너리 조작은 자바스크립트로 해야 한다) Python 이 가장 단순하고 좋은 듯 하다. 하지만 제작자는 발표 등을 할 때 node.js 를 많이 사용하는 모습을 보여주고 있다. FRIDA 의 가장 큰 장점은 다양한 플랫폼을 지원한다는 것이다. PIN 과는 달리 ARM 아키텍쳐를 지원하므로 Android, IOS 앱에도 적용이 가능하다. 또한 64 bit 에서도 정상적으로 동작한다.(awesome!!)
또한, 컴파일이 필요없는 스크립트 언어로 작성이 가능하다는 것도 매력적이다. 코드 수정이 빈번한 경우 매번 컴파일을 하는 것만큼 귀찮은 것은 없기 때문이다.
ETC(DinamoRIO, Valgrind, DynInst 등)
아직 해보지 않아서 잘 모름. Valgrind 의 경우 실제로 취약점을 꽤 많이 찾아준 것으로 알고 있다.
DBI 예제 (with FRIDA)
FRIDA 기본 원리
FRIDA 는 C/S 의 구조를 지원하기 위해 윈도우의 경우 DLL 인젝션을, *닉스 계열의 경우 라이브러리 인젝션을 수행한다. 그 후 API 후킹(주소값만 지정하면 유저 custom 함수도 가능), stalking(이벤트 기반) 기능 등을 이용하여 DBI 가 가능하다. 이때, 실제 DBI 를 수행하는 코드는 자바스크립트를 이용하여 작성해 주어야 한다.
FRIDA 설치
c:\> pip install frida // pip 는 python 모듈 관리를 위한 프로그램이며 이를 이용하여 쉽게 설치가 가능함
FRIDA 참고 자료 및 API
http://www.frida.re/docs/javascript-api // 아직 관련 자료가 많지 않아 공식 문서를 보는 것이 가장 좋다.
https://github.com/OALabs/frida-extract // frida 를 이용한 PE Extract 코드 (악성코드 등에서 PE 파일 추출)
FRIDA 예제 코드
아래 코드는 DBI 에 대한 개념이해를 위해 직접 발로 짠 코드이다. 간단하게 socket 관련 함수인 send() 함수를 후킹하여 버퍼를 기록하고, send() 함수를 호출한 코드 주소값들(BackTrace) 을 기록해주는 코드이다.
import sys
import pefile
import frida
def on_message(message, data):
# c/s 구조인 경우 메시지를 보낼 수 있다. 메시지를 처리할 핸들러를 여기에 작성
print "[%s] -> %s" % (message, data)
def main(target_process):
session = frida.attach(target_process) # attach => target 에 DLL 인젝션 수행
script = session.create_script(""" # 자바스크립트 로드(실질적인 DBI 코드)
var sendPtr = Module.findExportByName("ws2_32.dll", "send"); # send 함수 주소
console.log('send address: ' + sendPtr.toString());
console.log('>> Hooking ws2_32!send <<');
Interceptor.attach(sendPtr, { # send 함수에 후킹 설정(inline hooking 수행)
onEnter: function (args) { # 함수 실행 전 수행될 코드(인자값 기록, 변조 등 가능)
console.log("buf : " + Memory.readCString(args[1])); # 메모리에서 직접 read
console.log("send called from:" + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\\n") + " ");
},
onLeave: function (retval) { # 함수 실행 후 수행될 코드(리턴값 기록, 조작 등 가능)
}
});
""")
script.on('message', on_message) # 메시지 핸들러 설정
script.load()
raw_input('\n\n')
session.detach()
if __name__ == '__main__':
target_process = 'test.exe'
main(target_process)
실행
FRIDA 예제 코드2
이번에는 인자값 조작을 해 보자. send 로 전송되는 패킷 내용을 변조하는 코드이다. 위 코드와 거의 동일하며 함수 실행 전 인자값으로 넘어온 buffer 문자열을 조작한다.
import sys
import pefile
import frida
def on_message(message, data):
print "[%s] -> %s" % (message, data)
def main(target_process):
session = frida.attach(target_process)
script = session.create_script("""
var sendPtr = Module.findExportByName("ws2_32.dll", "send");
console.log('send address: ' + sendPtr.toString());
console.log('>> Hooking ws2_32!send <<');
Interceptor.attach(sendPtr, {
onEnter: function (args) {
console.log("buf : " + Memory.readCString(args[1]));
Memory.writeAnsiString(args[1],"HTTP/1.1 200 OK\\nServer: simple web server\\nContent-Type: text/html\\n\\nWelcome To My testServer !! ");
console.log("replaced buf : " + Memory.readCString(args[1]));
},
onLeave: function (retval) {
}
});
""")
script.on('message', on_message)
script.load()
raw_input('\n\n')
session.detach()
if __name__ == '__main__':
target_process = 'vul_http_server.exe'
main(target_process)
실행
'Reversing' 카테고리의 다른 글
WinDBG 고급 명령어들 (0) | 2017.06.07 |
---|---|
DBI - pin & pintool (4) | 2017.05.22 |
Embedded 기기 리버싱 - 펌웨어 리버싱 (1) | 2016.07.14 |
Windbg 기본 - (3) 분석시 유용한 명령어들 (2) | 2016.03.01 |
WinDBG 심볼 간편 설정 (0) | 2016.03.01 |
Embedded 기기 리버싱 - 펌웨어 리버싱
# 펌웨어 획득
- 벤더 홈페이지 다운
- 플래시메모리 덤프
# 펌웨어 분석 툴
- binwalk
root@kali:~/Desktop# binwalk -h
Binwalk v1.2.2-1 Craig Heffner, http://www.devttys0.com Usage: binwalk [OPTIONS] [FILE1] [FILE2] [FILE3] ... Signature Analysis: -B, --binwalk Perform a file signature scan (default) -R, --raw-bytes=<string> Search for a custom signature -A, --opcodes Scan for executable code signatures -C, --cast Cast file contents as various data types -m, --magic=<file> Specify an alternate magic file to use ... |
1) 펌웨어 시그니처 분석
root@kali:~/Desktop# binwalk n604s_kr_9_942.bin
DECIMAL HEX DESCRIPTION
-------------------------------------------------------------------------------------------------------------------
46692 0xB664 LZMA compressed data, properties: 0x5D, dictionary size: 16777216 bytes, uncompressed size: 209044 bytes
131072 0x20000 TRX firmware header, little endian, header size: 28 bytes, image size: 3788800 bytes, CRC32: 0x75B1E9D4 flags: 0x0, version: 1
131100 0x2001C LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 4378624 bytes
1565732 0x17E424 CramFS filesystem, little endian size 2351104 version #2 sorted_dirs CRC 0x9ee064f0, edition 0, 1954 blocks, 376 files
2) 펌웨어 아키텍쳐 분석
root@kali:~/Desktop# binwalk -A n604s_kr_9_942.bin | head -10
DECIMAL HEX DESCRIPTION
-------------------------------------------------------------------------------------------------------------------
9280 0x2440 MIPSEL instructions, function epilogue
9376 0x24A0 MIPSEL instructions, function epilogue
9992 0x2708 MIPSEL instructions, function prologue
10028 0x272C MIPSEL instructions, function epilogue
10276 0x2824 MIPSEL instructions, function prologue
10280 0x2828 MIPSEL instructions, function epilogue
10288 0x2830 MIPSEL instructions, function prologue
3) 펌웨어 엔트로피 분석
root@kali:~/Desktop# binwalk -E n604s_kr_9_942.bin
4) 펌웨어 파일시스템 추출
root@kali:~/Desktop# dd if=./n604s_kr_8_96.bin of=n604s_fs.bin bs=1 skip=1565732
2124820+0 records in
2124820+0 records out
2124820 bytes (2.1 MB) copied, 2.60455 s, 816 kB/s
root@kali:~/Desktop# file n604s_fs.bin
n604s_fs.bin: Linux Compressed ROM File System data, little endian size 2121728 version #2 sorted_dirs CRC 0x9094e641, edition 0, 1646 blocks, 353 files
5) 펌웨어 파일시스템 마운트
root@kali:~/Desktop# mkdir /n604fs
root@kali:~/Desktop# mount -t cramfs ./n604s_fs.bin /n604fs/
mount: warning: /n604fs/ seems to be mounted read-only.
root@kali:~/Desktop# cd /n604fs/
root@kali:/n604fs# ls
bin cramfs default dev etc home lib linuxrc ndbin plugin proc save sbin tmp usr var
6) 파일시스템 분석 후 fmk 를 이용하여 바이너리 수정/파일시스템 추가 등 조작 후 build
7) 만들어진 new-firmware.bin 이미지를 업데이트(관리자 페이지 수동 업데이트)
8) 간혹 업데이트 시 에러가 발생하는 경우 부트코드에서 검증을 수행하는 것
- 간단한 체크섬 (우회 쉬움)
- 암호화 (우회 어려움)
** 맥에서 바로 UART 시리얼 통신 확인하기
# screen /dev/tty.usbmodemfa2321 115200
# 부트코드 리버싱
=====================
- 펌웨어에서 부트코드 분리
# dd if=~~ of=~~ skip=~~ count=~~ bs=1
- 부트코드 아키텍쳐, load address, size 지정
=> file 명령, binwalk 결과값 이용
- load address 찾는 법
=> 부트코드이므로 bss 섹션 초기화 과정이 있을 것
=> li(or la), $0x80001000 등의 코드가 2번 연속으로 나오고 move $a1, $zero 루프 등으로 초기화 하는 부분을 찾음
=> 부트코드 | bss 섹션 과 같은 구조이므로 bss 섹션 시작주소에서 부트코드 사이즈를 빼 주면 시작주소가 나옴
=> bss 섹션 시작주소 - 부트코드 사이즈 = 부트코드 시작주소
- 부트중 펌웨어 해쉬값 검증 코드 등을 찾아서 패치
'Reversing' 카테고리의 다른 글
DBI - pin & pintool (4) | 2017.05.22 |
---|---|
DBI - Frida 를 이용한 DBI (3) | 2016.09.07 |
Windbg 기본 - (3) 분석시 유용한 명령어들 (2) | 2016.03.01 |
WinDBG 심볼 간편 설정 (0) | 2016.03.01 |
Windows Kernel Reversing - Object 분석 (0) | 2015.01.28 |
Windbg 기본 - (3) 분석시 유용한 명령어들
분석시 유용한 명령어 추가 정리.
# uf // 함수 디스어셈블, 함수 한번에 전체 디스어셈블, 분기문 보기좋게 보여줌 0:014> uf mshtml!CUndoPropChange::~CUndoPropChange mshtml!CUndoUnit::~CUndoUnit: 678dc2fd 8b4008 mov eax,dword ptr [eax+8] 678dc300 85c0 test eax,eax 678dc302 0f8580a92300 jne mshtml!CUndoUnit::~CUndoUnit+0x7 (67b16c88) mshtml!CUndoUnit::~CUndoUnit+0x16: 678dc308 c3 ret mshtml!CUndoUnit::~CUndoUnit+0x7: 67b16c88 50 push eax 67b16c89 6a00 push 0 67b16c8b ff351884dc67 push dword ptr [mshtml!g_hProcessHeap (67dc8418)] 67b16c91 ff15fc128967 call dword ptr [mshtml!_imp__HeapFree (678912fc)] 67b16c97 e96c56dcff jmp mshtml!CUndoUnit::~CUndoUnit+0x16 (678dc308) mshtml!CUndoPropChange::~CUndoPropChange: 67c03c81 8bff mov edi,edi 67c03c83 56 push esi 67c03c84 8bf0 mov esi,eax 67c03c86 57 push edi # uf /c // 함수 호출 관계만 보여줌 0:014> uf /c mshtml!CUndoPropChange::~CUndoPropChange mshtml!CUndoPropChange::~CUndoPropChange (67c03c81) mshtml!CUndoUnit::~CUndoUnit+0x10 (67b16c91): call to mshtml!_imp__HeapFree (678912fc) mshtml!CUndoPropChange::~CUndoPropChange+0x14 (67c03c95): unresolvable call: call dword ptr [ecx+8] mshtml!CUndoPropChange::~CUndoPropChange+0x1a (67c03c9b): call to mshtml!VariantClear (67a4b90d) # x // * 등을 사용하여 심볼 정보 확인, 클래스 정보 확인 등에 유용함 0:014> x mshtml!CUndoPropChange::~CUndoProp* // 뒷부분을 정확히 모를때 67c03c81 mshtml!CUndoPropChange::~CUndoPropChange (<no parameter info>) 0:014> x mshtml!CUndoPropChange::* // 해당 클래스 메소드 확인 67a5156c mshtml!CUndoPropChange::`vftable' = <no type information> 67c03c81 mshtml!CUndoPropChange::~CUndoPropChange (<no parameter info>) 67c03c22 mshtml!CUndoPropChange::CUndoPropChange (<no parameter info>) 67c03c51 mshtml!CUndoPropChange::`vector deleting destructor' (<no parameter info>) 67c03cdf mshtml!CUndoPropChange::PrivateDo (<no parameter info>) 67c03cae mshtml!CUndoPropChange::Init (<no parameter info>) 67c03c51 mshtml!CUndoPropChange::`scalar deleting destructor' (<no parameter info>) # dds // 4바이트씩 정리해서 심볼정보를 보여줌(문자열 포함) // 스택정보 파악 시 유용함 0:014> dds esp 05afd530 05774e50 05afd534 00477e58 05afd538 0048cb80 05afd53c 67c03c60 mshtml!CUndoAttrValueSimpleChange::`scalar deleting destructor'+0xf 05afd540 05afd57c 05afd544 05afd550 05afd548 678dc23d mshtml!CUndoUnitBase::Release+0x1e 05afd54c 00000001 05afd550 05afd58c 05afd554 67a6cfab mshtml!CImplPtrAry::ReleaseAll+0x21 05afd558 0048cb80 05afd55c 0048cb80 05afd560 06f3d030 05afd564 00000000 05afd568 678dc296 mshtml!CParentUnitBase::GetUnitType+0x82 05afd56c 06f3d030 05afd570 06f3d02c 05afd574 00000000 05afd578 05afd594 05afd57c 6789a594 mshtml!CStyleSheet::CAryFontFaces::`vftable' 05afd580 00000004 |
'Reversing' 카테고리의 다른 글
DBI - Frida 를 이용한 DBI (3) | 2016.09.07 |
---|---|
Embedded 기기 리버싱 - 펌웨어 리버싱 (1) | 2016.07.14 |
WinDBG 심볼 간편 설정 (0) | 2016.03.01 |
Windows Kernel Reversing - Object 분석 (0) | 2015.01.28 |
온라인 디컴파일러 - decompiler.fit.vutbr.cz (3) | 2014.10.31 |
WinDBG 심볼 간편 설정
WinDBG 심볼 간편 설정
WinDBG 를 사용하는 경우 심볼 설정을 해 주어야 윈도우 관련 DLL 심볼을 보며 편하게 리버싱을 할 수 있다. 여러가지 방법이 있으나 매일
까먹어서 정리해 둔다.
- WinDBG 심볼 패스 설정하기
SRV*c:\symbols*http://msdl.microsoft.com/download/symbols |
- 심볼 패스 쉽게 설정하기
0:000> .symfix c:\symbols 0:000> .reload |
- 심볼 패스 추가하기
0:000> .sympath+ c:\mysymbols 0:000> .reload |
이상 끝!
'Reversing' 카테고리의 다른 글
Embedded 기기 리버싱 - 펌웨어 리버싱 (1) | 2016.07.14 |
---|---|
Windbg 기본 - (3) 분석시 유용한 명령어들 (2) | 2016.03.01 |
Windows Kernel Reversing - Object 분석 (0) | 2015.01.28 |
온라인 디컴파일러 - decompiler.fit.vutbr.cz (3) | 2014.10.31 |
비주얼 베이직 리버싱 팁 - vb decompiler To IDC(ida script) (1) | 2013.12.23 |
Windows Kernel Reversing - Object 분석
제목은 커널 리버싱이지만, 단순히 툴 소개이다.(-.-;;) 애플리케이션 분석을 하다가도 커널에서 관리하는 구조체 등을
분석해야 하는 일이 자주 생긴다. 해서 이런 저런 자료들을 찾다보니 편리한 툴을 하나 찾았다.
Symbol Type Viewer 인데, 분석할 파일만 넣어주면 자동으로 Microsoft 심볼 서버와 연동해서 구조체들을 보여준다.
ntdll.dll. kernel32.dll 등의 파일의 구조체 정보가 유용하다.
아래 그림은 ntdll.dll 을 열어 본 화면이다.
.idc 로 export 해서 IDA Pro 에서 분석 정보로 활용할 수도 있다.
설명 끝~
'Reversing' 카테고리의 다른 글
Windbg 기본 - (3) 분석시 유용한 명령어들 (2) | 2016.03.01 |
---|---|
WinDBG 심볼 간편 설정 (0) | 2016.03.01 |
온라인 디컴파일러 - decompiler.fit.vutbr.cz (3) | 2014.10.31 |
비주얼 베이직 리버싱 팁 - vb decompiler To IDC(ida script) (1) | 2013.12.23 |
.net 프로그램 리버싱 툴 (1) | 2013.03.03 |
온라인 디컴파일러 - decompiler.fit.vutbr.cz
http://decompiler.fit.vutbr.cz
온라인으로 제공되는 디컴파일러 입니다. 상당히 유용하네요.
Arm , MIPS, 심지어 PowerPC 도 지원됩니다.
해보니 헥스레이처럼 간지(?)가 나진 않지만...무료이고 다양한 플랫폼을 지원하므로 급할때 유용합니다.
'Reversing' 카테고리의 다른 글
WinDBG 심볼 간편 설정 (0) | 2016.03.01 |
---|---|
Windows Kernel Reversing - Object 분석 (0) | 2015.01.28 |
비주얼 베이직 리버싱 팁 - vb decompiler To IDC(ida script) (1) | 2013.12.23 |
.net 프로그램 리버싱 툴 (1) | 2013.03.03 |
Windbg 기본 - (2) 기본 명령어들-2 (0) | 2012.08.08 |
비주얼 베이직 리버싱 팁 - vb decompiler To IDC(ida script)
심심풀이 워게임풀이 하던중 간만에 vb 문제가 나와서 vb로 디컴파일 후 분석을 하는데 정적분석만으론 풀 수 없는
문제라 ida 분석및 디버깅이 필요했다.
vb decompiler 를 이용해 얻은 정보들을 ida 로 그대로 옮길 수 있다.
map 파일을 생성해서 olly 등에서 참조할 수도 있으니 알아두자! :)
'Reversing' 카테고리의 다른 글
Windows Kernel Reversing - Object 분석 (0) | 2015.01.28 |
---|---|
온라인 디컴파일러 - decompiler.fit.vutbr.cz (3) | 2014.10.31 |
.net 프로그램 리버싱 툴 (1) | 2013.03.03 |
Windbg 기본 - (2) 기본 명령어들-2 (0) | 2012.08.08 |
Windbg 기본 - (1) 기본 명령어들 (0) | 2012.08.07 |
.net 프로그램 리버싱 툴
리버싱을 하다보면 가끔 닷넷 프로그램을 리버싱 해야 할 경우가 있다. 사실 나도 닷넷 프로그래밍을 공부해본 적은
없기 때문에 자세한 내부구조 까지는 알 수 없으나, 리버싱이 언제나 그렇듯이 중요한 건 프로그램에서 내가 고칠
부분을 찾고, 코드 패칭 등 원하는 작업을 할 수 있으면 되기 때문에 큰 어려움은 없었다.
가장 중요한 사실은 닷넷 프로그램은 관리코드 기반 언어이기 때문에 디컴파일이 매우 잘 된다는 것이다. :)
이번 코드 게이트 대회에서도 닷넷 프로그램이 문제에 나와서 나온 김에 정리를 해둔다.
# 닷넷 프로그램
- 관리 기반 코드 ( = java JVM처럼 중간언어로 컴파일됨, MSIL 이란 언어로 컴파일 됨 )
- 그러므로 디컴파일이 매우 쉽게 됨
- 난독화 솔루션 존재하나, 어느정도 원복해주는 툴 또한 존재함
# 관련 리버싱 툴
1) .net reflector ( 디컴파일러, http://www.red-gate.com/products/dotnet-development/reflector/ )
- 가장 많이 사용되는 닷넷용 디컴파일러 / .net 다양한 언어 지원 / 다양한 플러그인 지원 / 유료(ㅠㅠ)
[ 그림1 ] .net reflector
2) dotpeek ( 디컴파일러, http://www.jetbrains.com/decompiler/ )
- 최근에 알게된 닷넷용 무료(!) 디컴파일러 / 깔끔한 인터페이스 / 아직은 플러그인이 별로 없는 것이 단점
[ 그림 2 ] dotpeek
# 닷넷 reflector 유용한 필수 플러그인
1) Reflexil
- MSIL 언어 수정을 가능하게 해주는 플러그인
- MSIL 언어를 알아야함 =_=/ 아니면 소스 받아서 컴파이를 아예 다시 하거나~!
2) deblector
- 닷넷 디버깅 도우미(?)
- 리플렉터 상에서 디버깅을 하며 값 변경, 셋팅 등 일반적인 디버거의 기능을 추가해줌
# 코드게이트 문제 풀이
[ 그림 3 ] 코드게이트 binary 100 문제
문제를 열어보면 닷넷파일이고, 숫자키를 입력하게 되어 있다. 전형적인 crackme or keygen 문제이다.
닷넷이니 일단 디컴파일을 한 뒤 소스를 확인 해보면, 아래와 같은 비교 루틴을 찾을 수 있다.
TransFormable() 함수 내부를 살펴보면, 입력받은 키값이 16글자인지 비교한 뒤 , 입력받은 키값을 AES 함호화 하여
저장되어 있는 키값과 비교한다. 이 2 조건을 통과하면 정답을 출력하도록 되어 있다. 즉, 소스만으로 평문 키값을 알
아내긴 어렵다. 방법은 여러가지가 있겠지만, 여기선 플러그인을 활용하여 코드패칭을 하고 실행하여 바로 키값이 출
력되도록 할 것이다.
[ 그림 4 ] 키값 비교 및 정답 출력 함수
[ 그림 5 ] 무조건 정답출력 루틴으로 가도록 코드 패칭 ( ceq -> cgt 로 조작 )
[ 그림6 ] 파일명을 우클릭하여 Save as 로 패칭된 파일 저장
[ 그림 7] 정답화면
'Reversing' 카테고리의 다른 글
Windows Kernel Reversing - Object 분석 (0) | 2015.01.28 |
---|---|
온라인 디컴파일러 - decompiler.fit.vutbr.cz (3) | 2014.10.31 |
비주얼 베이직 리버싱 팁 - vb decompiler To IDC(ida script) (1) | 2013.12.23 |
Windbg 기본 - (2) 기본 명령어들-2 (0) | 2012.08.08 |
Windbg 기본 - (1) 기본 명령어들 (0) | 2012.08.07 |
Windbg 기본 - (2) 기본 명령어들-2
이전글에 이어서 Windbg 기본 명렁어 정리 중입니다.
역시 뭐든 안하면 까먹어요...열심히 합시다!!
- dt : dump variable info
dt [mod!]Name Field [Field]
ex) dt ntdll!_PEB
> dt !_PEB // PEB 구조체 확인
> dt !_PEB @$peb // 현재 프로세스 PEB 확인
+0x000 InheritedAddressSpace : 0 '' +0x001 ReadImageFileExecOptions : 0 '' +0x002 BeingDebugged : 0x1 '' +0x003 SpareBool : 0 '' +0x004 Mutant : 0xffffffff Void +0x008 ImageBaseAddress : 0x00400000 Void +0x00c Ldr : 0x00241ea0 _PEB_LDR_DATA +0x010 ProcessParameters : 0x00020000 _RTL_USER_PROCESS_PARAMETERS +0x014 SubSystemData : (null) +0x018 ProcessHeap : 0x00140000 Void +0x01c FastPebLock : 0x7c9ad600 _RTL_CRITICAL_SECTION +0x020 FastPebLockRoutine : 0x7c931000 Void |
- du : dump unicode string
> du 00401000 // 401000 유니코드
- dd : dump
> dd 0046c6b0 0046c6c4
0046c6b0 00000000 00000000 00000000 00000000
0046c6c0 00000000 00000000
- s : search (중요!)
0:014> s -a 00e70000 10071000 cmd
00ea8251 63 6d 64 00 00 00 00 2e-65 78 65 00 00 00 00 2e cmd.....exe.....
01f17152 63 6d 64 0d 0a 00 41 63-63 65 70 74 3a 20 61 70 cmd...Accept: ap
024f2d74 63 6d 64 2e 65 78 65 00-0d f0 ad ba 0d f0 ad ba cmd.exe.........
02520d3c 63 6d 64 2e 65 78 65 00-00 00 00 00 31 00 00 00 cmd.exe.....1...
02742d74 63 6d 64 2e 65 78 65 00-0d f0 ad ba 0d f0 ad ba cmd.exe.
- !heap : heap 메모리
0:014> !heap -stat
_HEAP 00dc0000
Segments 00000001
Reserved bytes 00010000
Committed bytes 00007000
VirtAllocBlocks 00000001
VirtAlloc bytes 00dc0050
_HEAP 003b0000
Segments 00000002
Reserved bytes 00110000
Committed bytes 00072000
VirtAllocBlocks 00000000
'Reversing' 카테고리의 다른 글
Windows Kernel Reversing - Object 분석 (0) | 2015.01.28 |
---|---|
온라인 디컴파일러 - decompiler.fit.vutbr.cz (3) | 2014.10.31 |
비주얼 베이직 리버싱 팁 - vb decompiler To IDC(ida script) (1) | 2013.12.23 |
.net 프로그램 리버싱 툴 (1) | 2013.03.03 |
Windbg 기본 - (1) 기본 명령어들 (0) | 2012.08.07 |
Windbg 기본 - (1) 기본 명령어들
그동안 손 놓고 있던 시스템 쪽을 다시 열심히 하기로 마음먹었다. 까먹지 않게 하나씩 다시 정리해야지.
다 까먹었다.... : (
# Windbg 기본 #
- 장점 : MS지원(symbol 등) / 강력한 커널디버깅 / 익숙해질시 편함
- 단점 : UI 가 불편함 = 단축키 익숙해지면 편함. 하지만 자꾸 까먹음
1) .help - 도움말 / .hh(F1도움말)
2) 디버깅
- .attach : attach
- .restart : 어플 재시작
- .detach : detach
- ctrl+break : 명령 콘솔(중지)
- g : 실행
- lm : list module
0:014> lm start end module name 00380000 00389000 Normaliz (deferred) 00400000 004be000 image00400000 (deferred) 00ba0000 00ca3000 comctl32_ba0000 (deferred) 00e70000 00f0f000 MSRMfilter01 (deferred) |
- !dmi : 모듈 상세정보
0:014> !lmi dnsapi Loaded Module Info: [dnsapi] Module: DNSAPI Base Address: 76ed0000 Image Name: C:\WINDOWS\system32\DNSAPI.dll Machine Type: 332 (I386) Time Stamp: 485bec2a Sat Jun 21 02:43:06 2008 Size: 27000 CheckSum: 24da0 |
- .tlist : tasklist
- !peb : process's environment block
- !teb : thread's environment block
- ~ : thread list
- bl : list breakpoints
- bc * : clear all br
- be # : enable bp #
- bd # : disable bp #
- bp [addr] : set br at addr
- ba [r|w|e] [size:1|2|4] addr : 특정 메모리 읽기/쓰기/실행 시 stop
ex) ba r4 7c9311dd
3) 팁
- 코드찾기
> s [시작주소] l [범위] [코드] [코드] [코드]
ex)
0:014> s 01c20000 l 9000 58 5b c3 01ee7f03 58 5b c3 21 4e 90 a0 b4-6e 34 c3 b5 3e 65 c4 02 X[.!N...n4..>e.. 0:014> u 01ee7f03 |
'Reversing' 카테고리의 다른 글
Windows Kernel Reversing - Object 분석 (0) | 2015.01.28 |
---|---|
온라인 디컴파일러 - decompiler.fit.vutbr.cz (3) | 2014.10.31 |
비주얼 베이직 리버싱 팁 - vb decompiler To IDC(ida script) (1) | 2013.12.23 |
.net 프로그램 리버싱 툴 (1) | 2013.03.03 |
Windbg 기본 - (2) 기본 명령어들-2 (0) | 2012.08.08 |