Ghidra - Script

안상준·2026년 1월 14일

Reversing

목록 보기
8/16

Ghidra Study

Script

이번 시간에 공부한 것은 Ghidra Scirpt 사용 방법이다.
코드 내에서 crash가 발생할 수 있는 지점을 찾기 위한 script를 간단하게 작성해 보았다.

먼저 Ghidra Script는
상단에 초록석 화살표 버튼을 누르면 여러 내장돼 있는 스크립트들이 뜨는 것을 확인할 수 있다.

이렇게 다양한 Script들이 존재하며 언어의 경우

이렇게 3가지를 지원한다.

Practice

실습을 직접 진행해 보았고 앞서 얘기한 crash 발생 가능성을 찾기 위해 사용자 입력이 있는 부분을 찾는 script를 작성해 보았다.

C Code

먼저 실습해 사용할 예제 C 코드다.

#include <stdio.h>

int main() {
    int n;
    int buff[100] = {0,};
    scanf("%d", &n);
    printf("%d\n", buff[n]);
    return 1;
}

아주 간단한 코드이며, 사용자의 입력이 buff의 크기를 넘게 되는 경우 crash가 발생하는 코드다.

Script Code

이제 사용자 입력을 찾는 script 작성해 보자.

먼저 간단하게 Assembly 코드를 살펴 보았는데, 아주 쉽게 입력을 받는 곳을 찾을 수 있다.
__mingw_scanf라는 함수를 찾기 위한 script 코드를 작성해 보았다.

// __mingw_scanf 호출 지점을 찾고 인자 정보를 분석합니다.
//@author Gemini
//@category Analysis
//@runtime Java

import ghidra.app.script.GhidraScript;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register;

public class FindInput extends GhidraScript {

    @Override
    public void run() throws Exception {
        String targetFunc = "__mingw_scanf";
        println("--- [분석 시작] " + targetFunc + " 추적 ---");

        SymbolTable symbolTable = currentProgram.getSymbolTable();
        SymbolIterator iter = symbolTable.getSymbols(targetFunc);

        while (iter.hasNext() && !monitor.isCancelled()) {
            Symbol sym = iter.next();
            if (sym.getSymbolType() == SymbolType.FUNCTION || sym.getSymbolType() == SymbolType.LABEL) {
                
                for (Reference ref : getReferencesTo(sym.getAddress())) {
                    if (ref.getReferenceType().isCall()) {
                        Address callAddr = ref.getFromAddress();
                        
                        // 호출 지점의 함수 정보 가져오기
                        Function caller = getFunctionContaining(callAddr);
                        if (caller != null && caller.getName().equals("main")) {
                            println("[!] 중요 입력 지점 발견 (in main)");
                        } else {
                            println("[+] 호출 발견: " + (caller != null ? caller.getName() : "Unknown"));
                        }

                        println("    - 주소: " + callAddr);
                        println("------------------------------------------");
                    }
                }
            }
        }
    }
}

직접 작성하지는 않았고, Gemini를 이용해 작성해 보았다.
간단하게 코드를 해석해 보면
1. SymbolTable을 가져온다.
2. SymbolTable 내에서 __mingw_scanf라는 이름의 심볼을 가져온다.
3. 위에서 찾은 함수의 주소를 가르키는 모든 지점을 찾는다.
4. 호출이 일어난 곳이 main함수 영역에 속해있는지 확인한다.
5. 찾은 함수가 위치한 주소를 출력

지금 script의 경우 특정 함수만을 대상으로 분석하는 코드이고, 이것을 확장하여 다양한 입력받는 코드를 탐지하도록 할 수 있다.

Result


실제로 실행한 결과이며,

찾은 주소와 main함수 내에서 호출하는 주소가 동일한 것을 확인할 수 있다.

Extension

위의 script는 실제로 crash가 발생할 수 있는 지점을 찾는 것은 아니기 때문에, 해당 함수를 통해 사용자의 입력값이 저장된 레지스터가 crash를 일으키는지 분석하는 부분도 필요하다.

0개의 댓글