> For the complete documentation index, see [llms.txt](https://www.pentestwiki.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.pentestwiki.com/defense-evasion/bypass-static-detection/function-pointer.md).

# 함수 포인터

함수 포인터는 함수의 주소를 저장하는 포인터이며, 원래의 함수 대신 포인터 함수를 사용함으로써 시그니처 기반 탐지와 IAT에 흔적을 남기지 않음으로서 탐지를 우회할 수 있습니다.

{% hint style="info" %}
소스코드 내 Windows API 호출 시 IAT에 흔적이 남는 반면, 함수 포인터는 남기지 않습니다.
{% endhint %}

<figure><img src="/files/3NjDeMKnFJaXNcqHP8r3" alt=""><figcaption><p>소스코드 내 Windows API 함수 호출의 기록(IAT)</p></figcaption></figure>

함수 포인터를 Windows API로 할당하는 문법은 다음과 같습니다.

```cpp
FARPROC pFunctionRaw = GetProcAddress('<kernel32.dll handle>', '<windows api name>');
typedef '<return type of windows api>'(WINAPI* pFunction)('<type1>', '<type2>' ...);
pFunction windowsAPI_fn = (pFunctionRaw)pFunction;
```

* kernel32.dll handle : Windows API가 저장된 kernel32.dll 등의 DLL 핸들
* windows api name : 우회하여 사용하고자 하는 Windows API 이름
* type : 사용하고자 하는 Windows API의 실제 매개변수 타입

다음과 같이 VirtualAlloc 함수를 사용하는 악성코드가 있으며, YARA 룰에서 VirtualAlloc이라는 글자를 탐지하고 있다고 가정하겠습니다.

```cpp
int main() {
	unsigned char shellcode[] = [...]
	void* code_memory;
	code_memory = VirtualAlloc(0, sizeof(shellcode), MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
}
```

VirtualAlloc 문자열은 string을 사용하여 문자열을 결합해 탐지를 우회합니다.

```cpp
	std::string first_char = "Virtual";
	std::string second_char = "Alloc";
	std::string all_char = first_char + second_char;
```

함수 포인터를 생성하는 방법은 위에서 언급한 문법대로 생성합니다.

이때는 우회하려는 함수의 실제 매개변수 타입대로 함수 포인터 타입을 정의해줘야 하며, VirtualAlloc의 매개변수 타입은 다음과 같습니다.

<figure><img src="/files/Et0kzWyn2ZwMkJFldkvE" alt=""><figcaption><p><a href="https://learn.microsoft.com/ko-kr/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc">https://learn.microsoft.com/ko-kr/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc</a></p></figcaption></figure>

```cpp
FARPROC pFunctionRaw = GetProcAddress(hKernel32, all_char.c_str());
typedef LPVOID(WINAPI* pVirtualAlloc)(LPVOID lpAddress, SIZE_T dwSize, DWORD  flAllocationType, DWORD  flProtect);
pFunction windowsAPI_fn = (pFunctionRaw)pFunction;
```

pFunctionRaw, pFuntion, windowsAPI\_fn 변수들은 임의의 이름으로 변경해도 무방하며, 최종적으로 수정한 코드는 다음과 같습니다.

```cpp
int main() {
	unsigned char shellcode[] = [...]
	void* code_memory;
	
	// kernel32.dll 로딩
	HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
	if (!hKernel32) {
		std::cout << "Failed to get kernel32.dll handle" << std::endl;
		return 0;
	}
	
	// 문자열을 자른다음 결합하여 변수로 관리
	std::string first_char = "Virtual";
	std::string second_char = "Alloc";
	std::string all_char = first_char + second_char;
	
	// VirtualAlloc 함수의 메모리 주소 획득
	FARPROC pVirtualAllocRaw = GetProcAddress(hKernel32, all_char.c_str());
	
	// 반환되지 않았다면 예외 처리
	if (!pVirtualAllocRaw) {
		std::cout << "Failed to get Virtual_Alloc function address" << std::endl;
		return 0;
	}
	
	// 함수 포인터 타입 선언
	typedef LPVOID(WINAPI* pVirtualAlloc)(LPVOID lpAddress, SIZE_T dwSize, DWORD  flAllocationType, DWORD  flProtect);
	
	// 함수 포인터 할당
	pVirtualAlloc VirtualAlloc_fn = (pVirtualAlloc)pVirtualAllocRaw;
	
	// 함수 포인터 사용
	LPVOID code_Memory = VirtualAlloc_fn(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
}
```

## Demo

<figure><img src="/files/QeHHFsiqtjQEEsbM8oGY" alt=""><figcaption></figcaption></figure>
