Ghidra에서 python으로 script를 작성해보자.
Ghidra를 켜면 이렇게 script manager를 켤 수 있는 버튼이 있다.
그러면 이렇게 이미 만들어져있는 많은 스크립트를 볼 수 있다.
직접 스크립트를 작성하기 위해서는 이 버튼을 눌러서 bundle manager를 실행시켜야 한다.
bundle manager를 보면 내가 작성한 스크립트가 저장될 것 같은 폴더가 not found...
그래서 새로운 폴더를 생성해 지정해보자.
그러면 이렇게 초록색으로 사용가능한 폴더가 추가되었다.
이제 이 폴더에 python으로 스크립트를 작성해 저장하면 된다.
그러면 이렇게 오른쪽에 script를 쓸 수 있는 창이 생긴다.
저장한 후 hello.py
를 더블클릭하면
이렇게 콘솔에 제대로 명령어가 출력되는 것을 볼 수 있다.
계속 ghidra.app.decompiler
같은 package를 import해서 사용하는 예제가 엄청 많은데 이렇게 Ghidra 내에서 스크립트를 작성해 사용하면 이걸 찾아서 install할 필요가 없는 것 같다.
솔직히 install 할 수 있는지도 모르겠다.
사실 저 패키지 없이는 유의미한 뭔가를 할 수 없는 상황이었어서 어떻게든 살아보려고(?) 설치 방법을 찾는 도중 찾은 방법이다.
교수님께 여쭤보니 기드라 외부에서 코드를 돌리는건 고오급기술이라 복잡하다고 하심. 내부에서 해결하자.
Ghidra의 Window - Python에서 Python shell을 열 수 있다!
짤막한 snippet을 몇 개 더 실행해보자.
이 snippet은 여기에서 구한 것이다.
내가 이 snippet을 적용한 코드는 유명한 abex' crackme 이다.
그냥 검색하면 다운받을 수 있는데 검색하면 나오는 블로그 중 하나 링크를 단다.
snippet 중 아래를 보자.
value = 0x00401010
## transform to a Ghidra Address object
addr = toAddr(value)
## get the containing function
fn = getFunctionContaining(addr)
## get the function's entry point
entry = fn.getEntryPoint()
print(addr)
print(fn.getName())
print(entry.toString())
value
의 값은 내가 임의로 바꾼 것이다. 이 value
의 값은 Ghidra로 확인할 수 있는 function 안에 속한 주소이다.
위의 snippet을 실행하면 value
에 담긴 주소를 toAddr()
에 넣어 그 address를 addr
에 넣는다.
그리고 getFunctionContaining()
을 통해 addr
를 담고 있는 function을 fn
에 넣는다.
getEntryPoint()
를 사용하면 fn
의 entry point를 entry
에 담을 수 있다.
위의 script를 실행시킨 결과는 다음과 같다.
함수의 이름은 entry()
, entry point의 주소는 0x00401000
이다.
초기 value
의 값은 function의 entry point인 0x00401000
이 될 수도 있다.
함수 entry()
내의 모든 주소는 다 같은 결과가 나온다.
다음 snippet을 보자.
## let fn be a function
callers = fn.getCallingFunctions(monitor)
print(callers)
callees = fn.getCalledFunctions(monitor)
print(callees)
이 snippet은 function의 caller와 callee를 출력해준다.
실행결과는 아래와 같다.
결과를 보면, entry()
를 호출한 caller는 없고, entry()
가 호출한 callee는 총 3개임을 확인할 수 있다.
기존의 결과와 동일함을 확인할 수 있다.
다음 snippet을 보자.
import ghidra.app.decompiler as decomp
## let addr be a valid Address
fn = getFunctionContaining(addr)
## get the decompiler interface
iface = decomp.DecompInterface()
## decompile the function
iface.openProgram(fn.getProgram())
d = iface.decompileFunction(fn, 5, monitor)
## get the C code as string
if not d.decompileCompleted():
print(d.getErrorMessage())
else:
code = d.getDecompiledFunction()
ccode = code.getC()
print(ccode)
위의 code는 addr
(위처럼 valid한, 함수 내부의 address)를 주면 그것을 가지고 decompile interface인 iface
를 얻는다.
그것을 가지고 decompile해서 그 결과를 C로 출력하는 코드이다.
결과는 다음과 같다.
[참고자료]
https://hackyboiz.github.io/2021/03/07/idioth/ghidra_part2/
https://deadc0de.re/articles/ghidra-scripting-python.html