Ghidra Function Signature 편집 방법
미국 NSA 에서 개발한 무료 리버스 엔지니어링 프레임워크 툴인 Ghidra 는 훌륭한 코드 디컴파일 기능을 제공하지만 항상 적절하게 디컴파일하는건 아니다. 이러한 경우 중 하나는 함수의 Calling Convention을 적절하게 인지하지 못하는 것으로, 이 경우엔 분석가가 직접 함수의 Caller, Calle 코드를 분석해 Function Signature 를 적절하게 수정하지 않으면 디컴파일된 코드가 읽기 어렵거나 코드의 본래 의도를 반영하지 못 한다.
이 글에서는 Ghidra 의 Function Signature를 편집해 디컴파일된 코드 결과에 반영하는 방법에 대해 설명한다.
1. 테스트 샘플
테스트 샘플은 MalwareBazaar 에서 다운로드할 수 있다. 해당 파일은 시스템 감염 기능을 가진 멀웨어이므로 반드시 격리된 환경에서만 테스트하기를 권고한다.
- MD5: D3A26B77773975EBEB5245B4E09207C2
- SHA-256: 5FDD5716C9D4C5B5EDDE34644094E7BD4492DD64426A94B55ED39C2BB6393526
- 파일 크기: 294,064 바이트
- 파일 타입: PE32 EXE

2. Function Signature 편집
앞서 소개한 테스트 샘플의 FUN_00405250 함수를 대상으로 Function Signature 편집 기능을 테스트할 거다. 이 함수는 프롤로그 코드에서 EAX 레지스터 값을 dword ptr [EBP + local_8] 에 저장한 후, 해당 주소를 CALL 로 호출하는 동적 호출 코드를 가지는 wrapping 함수다.


다음은 FUN_00405250 함수를 호출하는 Caller 코드다. 함수 호출 전 EAX 레지스터에 LAB_004082a0 주소를 저장하는 것으로 보아 해당 주소의 함수를 동적으로 호출하려는 의도가 분명하다. 하지만 디컴파일된 코드는 최근 2번째로 Push 된 0x3을 첫 번째 인자로 전달하여 함수 본래의 의도를 적절히 해석하지 못하고 있다.


Ghidra 가 함수 Signature를 제대로 해석하지 못하고 있으니 적절하게 변경할 필요가 있다. 해당 함수는 첫 번째 인자를 EAX 레지스터에, 동적으로 호출되는 함수에 전달할 인자들을 스택에 저장하지만 이 글에서는 FUN_00405250 함수의 인자를 변경하는 점에 대해서만 중점적으로 다룬다.
FUN_00405250 함수로 이동 후, 함수를 우클릭하고 Edit Function Signature 를 클릭한다.

현재 Calling Convention 은 __cdecl다. 우리 필요에 맞게 변경해야 하니 우측의 Use Custom Storage 를 체크해야 한다.

이제 파라미터를 변경해야 한다. 앞선 코드를 분석해 EAX를 첫 번째 인자로 삼기로 결정했다. 현재 Stack[0x4]:4 를 첫 번째 인자로 사용하는 param_1 을 클릭, 우측의 X 버튼을 클릭해 제거한다.

이후 우측의 + 버튼을 클릭해 새로운 param_1을 생성, <UNASSIGNED> 상태인 Storage 를 더블 클릭해 Storage Address Editor를 팝업시킨다. 4바이트 크기 공간을 차지하는 EAX 레지스터를 사용하며, 데이터 타입은 함수 주소이므로 DWORD* 를 사용했다.

변경된 Signature를 적용하면 FUN_00405250 함수의 디컴파일된 코드가 의도대로 param_1 주소를 함수로서 호출하도록 변경된 것을 확인할 수 있다.

Caller 코드도 디컴파일 코드가 변경되어 분석한 의도대로 LAB_004082a0 주소를 인자로 전달하고 있다.
