# 함수 포인터

함수 포인터는 함수의 주소를 저장하는 포인터이며, 원래의 함수 대신 포인터 함수를 사용함으로써 시그니처 기반 탐지와 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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.pentestwiki.com/defense-evasion/bypass-static-detection/function-pointer.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
