The file is a DLL and should be started as such. The file contains a small hint on how it should be used in a string:

rundll32.exe payload.dll, EntryPoint EntryPoint

Running this, however, yields an error; which is weird, because the DLL does export a function named EntryPoint. Turns out, when the DLL is loaded and DllMain is executed, the sneaky DLL changes it’s own export table and erases the function name. That means the function should be called by ordinal (the number in the export table).

There’s two approaches for this; one is using rundll32.exe like rundll32.exe payload, #1, or by rigging up a simple loader in C. I decided on the last one for flexibility purposes:

int main()
{
	int procOrdinal = 1;

	HMODULE hDLL = LoadLibraryA("payload.dll");
	if (!hDLL) {
		printf("%d", GetLastError());
		system("pause");
	}
	HANDLE hModule = GetModuleHandleA("payload.dll");
	printf("Base address: %p\n", hModule);

	FARPROC hidden = GetProcAddress(hDLL, MAKEINTRESOURCEA(procOrdinal));
	hidd = (plfunc)hidden;
	printf("Proc address: %p - %p\n", hidden, ((uint64_t)hidden - (uint64_t)hModule));

	hidd(0, 0, "", 0);
}

Printing the addresses makes debugging a lot easier due to ASLR. It took a few guesses to get the calling convention right, but in the end a messagebox appeared!

Insert clever error message here!

This was because the third argument wanted a password. This was easy to patch out in the DLL by patching out the jump at 0x180005b1f. Then I started to get somewhere:

Part of the key appears

Running the executable over again, the same part keeps appearing. So we’ll need to do something to make it show other key parts.

When the DLL loads, it takes an address from a table at an index determined by a global variable and calls a function to decode that. Manipulating that global variable after load just before the code is decrypted caused the DLL to crash, so we’ll need to trace back where the index comes from.

At some point, a call to GetSystemTime() caught my eye in the debugger. Turns out, there is a function at 0x180004710 that is called to determine the index, based on some math with the current month.

Index determining function

Manipulating RAX at this point made different key parts appear each time the DLL was loaded. Putting the key parts together gave the flag!