* Main loader code. */
| 457 | * Main loader code. |
| 458 | */ |
| 459 | void *e9loader(PEB *peb, const struct e9_config_s *config) |
| 460 | { |
| 461 | // Step (0): Sanity checks & initialization: |
| 462 | const uint8_t *loader_base = (const uint8_t *)config; |
| 463 | const uint8_t *image_base = loader_base - config->base; |
| 464 | void *entry = (void *)(image_base + config->entry); |
| 465 | static bool inited = false; |
| 466 | if (inited) |
| 467 | return entry; // Enforce single execution |
| 468 | inited = true; |
| 469 | |
| 470 | // Step (1): Parse the PEB/LDR for kernel32.dll and our image path: |
| 471 | PEB_LDR_DATA* ldr = peb->Ldr; |
| 472 | LIST_ENTRY *curr = ldr->InMemoryOrderModuleList.Flink; |
| 473 | const uint8_t *kernel32 = NULL, *user32 = NULL, *ntdll = NULL; |
| 474 | const wchar_t *self = NULL; |
| 475 | |
| 476 | while (curr != NULL && curr != &ldr->InMemoryOrderModuleList && |
| 477 | (kernel32 == NULL || self == NULL || user32 == NULL)) |
| 478 | { |
| 479 | const LDR_DATA_TABLE_ENTRY* entry = |
| 480 | CONTAINING_RECORD(curr, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); |
| 481 | const UNICODE_STRING *name = &entry->FullDllName; |
| 482 | if (entry->DllBase == (void *)image_base) |
| 483 | self = name->Buffer; |
| 484 | name++; // BaseDllName immediately follows FullDllName |
| 485 | if (e9wcscasecmp(name->Buffer, L"kernel32.dll") == 0) |
| 486 | kernel32 = (const uint8_t *)entry->DllBase; |
| 487 | else if (e9wcscasecmp(name->Buffer, L"ntdll.dll") == 0) |
| 488 | ntdll = (const uint8_t *)entry->DllBase; |
| 489 | else if (e9wcscasecmp(name->Buffer, L"user32.dll") == 0) |
| 490 | user32 = (const uint8_t *)entry->DllBase; |
| 491 | curr = curr->Flink; |
| 492 | } |
| 493 | if (kernel32 == NULL || self == NULL) |
| 494 | e9panic(); |
| 495 | |
| 496 | // Step (2): Get critical functions necessary for output: |
| 497 | get_proc_address_t GetProcAddress = |
| 498 | (get_proc_address_t)e9get(kernel32, "GetProcAddress"); |
| 499 | if (GetProcAddress == NULL) |
| 500 | e9panic(); |
| 501 | attach_console_t AttachConsole = |
| 502 | (attach_console_t)GetProcAddress(kernel32, "AttachConsole"); |
| 503 | get_std_handle_t GetStdHandle = |
| 504 | (get_std_handle_t)GetProcAddress(kernel32, "GetStdHandle"); |
| 505 | if (AttachConsole == NULL || GetStdHandle == NULL) |
| 506 | e9panic(); |
| 507 | (void)AttachConsole(-1); |
| 508 | void *stderr = GetStdHandle(STD_ERROR_HANDLE); |
| 509 | write_console_t WriteConsole = |
| 510 | (write_console_t)GetProcAddress(kernel32, "WriteConsoleA"); |
| 511 | if (WriteConsole == NULL) |
| 512 | e9panic(); |
| 513 | |
| 514 | if (config->magic[0] != 'E' || config->magic[1] != '9' || |
| 515 | config->magic[2] != 'P' || config->magic[3] != 'A' || |
| 516 | config->magic[4] != 'T' || config->magic[5] != 'C' || |
nothing calls this directly
no test coverage detected