{ enessakircolak }

API-Resolving

May 16, 2023
3 minutes

API Resolving

Although it has a functional use, it can be abused quite simply, causing disruption in the analysis process.
This technique, which can be handle very quickly if known, will cause you to show an incomplete report to your potential readers if unknown or overlooked :))

If so, why does Microsoft allow this?

In fact, it is aimed to help us do dynamic programming. In some functions, you may come across the phrase may be altered or unavailable in future versions. Since these functions cannot be reached with a direct call, we need to call them by taking their address. Of course, by using this approach for current functions, the can aim to not see which APIs are used during static analysis. So, when the technique is easy, all kinds of additions are made in order to diversify it even more. If you like the technique, I suggest you also research API HASHING.



C++

void message() {
	while (1)
		std::cout << "message\n";
}

int main()
{
	string str = "rCTPETeYCTPU";  // CreateThread xor 1 
	string Func;
	char key = '1';

	for (int i = 0; i < str.length(); i++)
		Func += str[i] ^ key;  // Func = CreateThread
	
	typedef DWORD(WINAPI* MyFuncPtr)(LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD); // CreateThread Fonksiyonunun parametreleri aynı olan bir fonksiyon tanımlıyoruz
	MyFuncPtr RUN = (MyFuncPtr)GetProcAddress(LoadLibrary(L"Kernel32.dll"), Func.c_str()); // GetProcAddress ile Func değişkenindeki API'nin adresini alıyoruz
	RUN(NULL, 0, (LPTHREAD_START_ROUTINE)message, NULL, 0, NULL); // Artık CreateThread gibi çalıştırabiliriz

	while (1)
		std::cout << "MAIN\n"; // programı çalıştırarak konsolda "MAIN" ve "message" yazılarını gözlemleyebilirsiniz. 
}



cff.png


It doesn’t seem to use any CreateThread API.

Practice


ida2
While compiling the code in the image, encryption was not applied, it is clearly seen which function was called.

ida1


Although the technique is known, in order to understand the function to be called here, it must be either decrypted or dynamically arrived at.
Let's go one step further. The GetProcAddress we use gives us a address dynamically, as DWORD type. What if we try to take it as static?
There is a small risk, of course, but let's grasp the theory first.

load

The eax value 75D50000 after the LoadLibrary call. This is the starting address of Kernel32.dll, but we need CreateThread in it and when we call GetProcAddress for reach the CreateThread address we can see it in eax “75D6CBC0”.

proc
The difference is “1CBC0”, that is, if we add this difference to the variable we assigned the LoadLibrary value to, we will actually reach the CreateThread address.


The problem is that after a minor update the CreateThread address in the file may change. Therefore, the value we assign static will show a completely different address, so it will be inoperable. In this case you will need to check the version and run it. How hard you try now is up to you :))

~Fall in love with the process, and the results will come.