visual studio를 사용했습니다.
New -> Project -> Dynamic-Link Library (DLL)
로 프로젝트를 만든 후 아래와 같이 c파일을 하나 만듭니다.
#include "pch.h"
#include <windows.h>
#include <stdio.h>
__declspec(dllexport) short add(short a, short b) {
return a + b;
}
__declspec(dllexport) void fuzz_entry(const unsigned char* data, size_t size) {
if (size < 4) return;
short a = *(short*)(data);
short b = *(short*)(data + 2);
short arr[22222];
for (int i = 0; i < 22222; i++) {
arr[i] = i;
}
short c = add(a, b);
arr[c] = 0;
printf("add(%d, %d) = %d\n", a, b, c);
}
C언어 임을 명시하기 위해 Project -> Property -> C/C++ -> Advanced -> Compile As
의 값을 Compile as C Code (/TC)
로 변경합니다. 이후 Ctrl + Shift + B
로 빌드하면 프로젝트\x64\Debug
에 dll이 빌드됩니다.
눈에 띄는 것은 pch.h, windows.h, dllexport 가 있습니다.
이번에는 DDL이 아닌 Console App
으로 로젝트를 만든 후 아래와 같이 c파일을 만듭니다.
#include <windows.h>
#include <stdio.h>
typedef int (*AddFunc)(int, int);
int main() {
HMODULE hDll = LoadLibraryA("testdll.dll");
if (!hDll) {
printf("DLL 로드 실패\n");
return 1;
}
AddFunc add = (AddFunc)GetProcAddress(hDll, "add");
if (!add) {
printf("함수 찾기 실패\n");
return 1;
}
int result = (int)add(1, 2);
printf("1 + 2 = %d\n", result);
FreeLibrary(hDll);
return 0;
}
마찬가지로 C로 exe파일로 빌드합니다. dll파일을 exe에 동일한 위치에 두고 exe를 실행하면 정상적으로 1 + 2 = 3
을 출력합니다.
프로그램 실행 중 필요한 시점에서 dll을 로드하고 해제할 수 있습니다.
아래와 같이 winafl을 빌드합니다.
# git clone winafl
# cd winafl
mkdir build32
cd build32
cmake -G"Visual Studio 17 2022" -A Win32 .. -DDynamoRIO_DIR=C:\DynamoRIO\cmake
cmake --build . --config Release
# git clone winafl
# cd winafl
mkdir build64
cd build64
cmake -G"Visual Studio 17 2022" -A x64 .. -DDynamoRIO_DIR=C:\DynamoRIO\cmake
cmake --build . --config Release
위에서 만든 dll을 기반으로 harness 코드를 작성합니다.
#include <windows.h>
#include <stdio.h>
typedef void (*FuzzEntryFunc)(const unsigned char*, size_t);
int main(int argc, char* argv[]) {
if (argc < 2) {
printf("Usage: harness.exe <fuzz input file>\n");
return 1;
}
HMODULE hDll = LoadLibraryA("testdll.dll");
if (!hDll) {
printf("DLL 로드 실패\n");
return 1;
}
FuzzEntryFunc fuzz_entry = (FuzzEntryFunc)GetProcAddress(hDll, "fuzz_entry");
if (!fuzz_entry) {
printf("함수 찾기 실패\n");
FreeLibrary(hDll);
return 1;
}
FILE* file = nullptr;
if (fopen_s(&file, argv[1], "rb") != 0) {
printf("퍼징 데이터 파일 열기 실패\n");
FreeLibrary(hDll);
return 1;
}
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
fseek(file, 0, SEEK_SET);
unsigned char* data = (unsigned char*)malloc(size);
fread(data, 1, size, file);
fclose(file);
fuzz_entry(data, size);
free(data);
FreeLibrary(hDll);
return 0;
}
C:\\winafl\\input
에 예시 입력(ex. \x01\x02\x03\x04
)을 여러 개 넣었습니다.
아래의 명령어로 퍼징을 시작합니다.
# cd winafl
cd build64/bin/Release
afl-fuzz.exe -D C:\DynamoRIO-Windows-11.3.0-1\bin64 ^
-i "C:\\winafling\\input" -o "C:\\winafling\\output" -t 5000 -- ^
-coverage_module testdll.dll -target_module testdll.dll -target_method fuzz_entry ^
-fuzz_iterations 5000 -nargs 1 -- ^
C:\winafling\testharness.exe @@
WinAFL 1.17 based on AFL 2.43b (testharness.exe)
+- process timing -------------------------------------+- overall results ----+
| run time : 0 days, 0 hrs, 4 min, 18 sec | cycles done : 42 |
| last new path : 0 days, 0 hrs, 3 min, 44 sec | total paths : 5 |
| last uniq crash : 0 days, 0 hrs, 4 min, 17 sec | uniq crashes : 2 |
| last uniq hang : none seen yet | uniq hangs : 0 |
+- cycle progress --------------------+- map coverage -+----------------------+
| now processing : 3 (60.00%) | map density : 0.07% / 0.08% |
| paths timed out : 0 (0.00%) | count coverage : 1.21 bits/tuple |
+- stage progress --------------------+ findings in depth --------------------+
| now trying : splice 1 | favored paths : 1 (20.00%) |
| stage execs : 95/96 (98.96%) | new edges on : 3 (60.00%) |
| total execs : 327k | total crashes : 453 (2 unique) |
| exec speed : 1406/sec | total tmouts : 0 (0 unique) |
+- fuzzing strategy yields -----------+---------------+- path geometry -------+
| bit flips : 0/96, 0/93, 0/87 | levels : 2 |
| byte flips : 0/12, 0/9, 0/3 | pending : 0 |
| arithmetics : 0/672, 0/563, 0/0 | pend fav : 0 |
| known ints : 0/45, 0/285, 0/120 | own finds : 2 |
| dictionary : 0/0, 0/0, 0/0 | imported : n/a |
| havoc : 3/121k, 1/204k | stability : 94.23% |
| trim : n/a, 0.00% +-----------------------+
+-----------------------------------------------------+ [cpu000001: 13%]
의도한 uniq crashes; Array Index Out of Bounds Exception
, Overflow
2개 모두 발견됐습니다.