{
	"id": "0fd6b6c6-2108-4a88-bbb3-b5b8a97a7444",
	"created_at": "2026-04-06T01:32:07.435814Z",
	"updated_at": "2026-04-10T13:12:02.061906Z",
	"deleted_at": null,
	"sha1_hash": "7855b159d34a19521e0b8ea0af2fa544fa1ac667",
	"title": "BlackLotus-analysis-stage2-bootkit-rootkit-stage",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 102048,
	"plain_text": "BlackLotus-analysis-stage2-bootkit-rootkit-stage\r\nPublished: 2023-05-29 · Archived: 2026-04-06 00:48:04 UTC\r\n⌘Ctrlk\r\nBlackLotus-analysis-stage2-bootkit-rootkit-stage\r\nBlackLotus stage 2 bootkit-rootkit analysis\r\nBefore we dive into this divine shit(belive me this is some divine shit as nobody can do this withouth GOD's\r\nWill(at least that's my opinion on this)) ,here's the hash for the bootkit file\r\nFrist things first this is how a healthy system looks like\r\nC:\\Windows\\system32\u003eBCDEdit\r\nWindows Boot Manager\r\n--------------------\r\nidentifier {bootmgr}\r\ndevice partition=\\Device\\HarddiskVolume9\r\npath \\EFI\\MICROSOFT\\BOOT\\BOOTMGFW.EFI\r\ndescription Windows Boot Manager\r\nlocale en-US\r\ninherit {globalsettings}\r\ndefault {current}\r\nresumeobject {3f80ecd0-df10-11ed-bafc-80a84b2564bb}\r\ndisplayorder {current}\r\ntoolsdisplayorder {memdiag}\r\ntimeout 30\r\nWindows Boot Loader\r\n-------------------\r\nidentifier {current}\r\ndevice partition=C:\r\npath \\Windows\\system32\\winload.efi\r\ndescription Windows 10\r\nlocale en-US\r\ninherit {bootloadersettings}\r\nrecoverysequence {3f80ecd2-df10-11ed-bafc-80a84b2564bb}\r\ndisplaymessageoverride Recovery\r\nrecoveryenabled Yes\r\nisolatedcontext Yes\r\nallowedinmemorysettings 0x15000075\r\nosdevice partition=C:\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 1 of 14\n\nsystemroot \\Windows\r\nresumeobject {3f80ecd0-df10-11ed-bafc-80a84b2564bb}\r\nnx OptIn\r\nbootmenupolicy Standard\r\nNow on my analysis i never managed to infect my machine such i will use the example from the already\r\nreferenced asian's researcher blog post which this is how it's supposed to look an infected one\r\n // Windows Boot Manager\r\n // --------------------\r\n // identifier {9dea862c-5cdd-4e70-acc1-f32b344d4795}\r\n // description Windows Boot Manager\r\n // locale en-US\r\n // inherit {7ea2e1ac-2e61-4728-aaa3-896d9d0a9f0e}\r\n // bootdebug Yes\r\n // displayorder {57e1b615-0355-11ec-abb0-005056c00008}\r\n // timeout 30\r\n // Windows Boot Loader\r\n // -------------------\r\n // identifier {57e1b615-0355-11ec-abb0-005056c00008}\r\n // device boot\r\n // path \\system32\\hvloader.efi\r\n // description Hoy la disco se flota\r\n // locale en-US\r\n // inherit {6efb52bf-1766-41db-a6b3-0ee5eff72bd7}\r\n // truncatememory 0x10000000\r\n // avoidlowmemory 0x1000\r\n // nointegritychecks Yes\r\n // testsigning Yes\r\n // isolatedcontext Yes\r\n // osdevice boot\r\n // systemroot \\\r\n // ems Yes\r\n=============================================================================\r\n=============================================================================\r\nBefore we get started how does one setup the environment for the analysis of an efi module anyway ? Well\r\ncourtesy goes to @MaverickMusic__ , during a disscussion with him he handed me this( https://zhuanlan-zhihu-com.translate.goog/p/343293521?_x_tr_sl=auto\u0026_x_tr_tl=en\u0026_x_tr_hl=en-GB ). Now i didn't completly\r\nfollow the stepts there so here's what exactly i did in order to have the environment up and running :\r\n-First i installed edk2(https://github.com/tianocore/tianocore.github.io/wiki/Windows-systems)\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 2 of 14\n\n-Second i have configured my ovmf as debug not realease(this will help us later). Here is the command build -a\r\nX64 -t VS2019 -b DEBUG -p OvmfPkg/OvmfPkgX64.dsc\r\n-Third i had to configure my windbg. How tf did i do this ? I downloaded everything from this link( git clone\r\nhttps://github.com/microsoft/WinDbg-Samples ). Than i compiled ExdiGdbSrv.sln. Thank i followed everything\r\nfrom this link(https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/setting-up-qemu-kernel-mode-debugging-using-exdi), from whevere it said Use regsvr32 to register the DLL in an Administrator\r\ncommand prompt. till PS\u003e.\\Start-ExdiDebugger.ps1 -ExdiTarget \"QEMU\" -GdbPort 1234 -Architecture x64 -\r\nExdiDropPath \"C:\\path\\to\\built\\exdi\\files\" . Confusing i know but please wait patiencly as i will defently\r\nmake a video where i will explain every step! Cool so now that we have a setup environment for debugging how tf\r\ndo we debug the code ? So we start qemu in my case i did it by executing qemu-system-x86_64.exe -L . -bios\r\nOVMF.fd -hdd dos.img -debugcon file:debug.log -global isa-debugcon.iobase=0x402 . Once i ran qemu\r\ncommmand i instantly went and selected compat_monitor0 from view menu of qemu. It should look like that\r\nwhen you do that.\r\nalso after selecting this you should input gdbserver to start a remeote instance of gdb debuggin to which we will\r\nattach with windbg using this command .\\Start-ExdiDebugger.ps1 -ExdiTarget \"QEMU\" -GdbPort 1234 -\r\nArchitecture x64 Cool so once we connect to it will look like this\r\nSo how do we set up a breakpoint in order to debug the bootkit? Well that's we we compiled the ovmf image as de\r\nSo cool now to make sense of this output, for our case the only relevant line is EntryPoint=0x000062C9A8C\r\nwhich is like the preffered loaded address whenever we run the bootkit. Specifically for the bootkit it varies\r\nbetween 0x62C4A8C or 0x62C9A8C . Now we can rebase the program in ida and do our normal work :) . Enojoy\r\nthe rest of the blog!\r\n=============================================================================\r\nBindiffing the original winload.efi with the one dropped by the blacklotus\r\nWe see some similarities but also some discepancies, but nothing usefull,anywayy....\r\n=============================================================================\r\nCool so let's get this party started.\r\nCool so let's start dissecating. So first we see that we have a function which gets called. Cool so what about it ?\r\nwell\r\nCool another function . Not quite... Notice something familiary ?\r\nNothing yet???\r\nNo problemo maybe now\r\nSame demangle function! Hi there old friend :)))\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 3 of 14\n\nCool but what about return (*(a1 + 88))(v2, \u0026unk_62CEABC, 3i64); ?? Well honestly idk what to say just\r\nsoley from a static perspective so let's try to use the debugger to understand it :))\r\nSo when we demangle the string we get\r\nSo next when we end up to the call instruction\r\nand we get no info.... great, but why is that ? bc we don't have a .pdb file so we can get debug symbols.... Cool at\r\nleast ida is helpfull here. So we know that the \"grand\" function takes as input SystemTable-\u003eRuntimeServices,\r\nwhich is of type EFI_SYSTEM_TABLE. Cool if we inspect it this is a A pointer to the EFI Runtime Services\r\nTable. . if we search around googler we come around a bunch of docs but one crucial doc we come around is\r\nhttps://uefi.org/sites/default/files/resources/UEFI_Spec_2_1_D.pdf . there is says\r\nCool so a struct with bunch of pointers, ye, but let's zoom in more.\r\nSo first it demangles VbsPolicyDisable, if we search google we come around eset analysis which states that\r\nthis variable is evaluated by the Windows OS loader during boot and if defined, the core VBS features,\r\nsuch as HVCI and Credential Guard will not be initialized. , so basically this variable is responsible for\r\ncurrent \"security\" at boot level. Cool next we have the function which takes that variable and\r\nand so we can come to the conclusion that this must be a function which changes somehow the state of that\r\nvariable. Cool so what are some possible function that could do this ? there's only one such function in\r\nEFI_SYSTEM_TABLE which EFI_SET_VARIABLE SetVariable;\r\nSo we conclude that this function simply take VbsPolicyDisable and sets it to\r\ndb 77h ; w\r\n.data:0000000180005034 db 59h ; Y\r\n.data:0000000180005035 db 3\r\n.data:0000000180005036 db 32h ; 2\r\n.data:0000000180005037 db 4Dh ; M\r\n.data:0000000180005038 db 0BDh ; ½\r\n.data:0000000180005039 db 60h ; `\r\n.data:000000018000503A db 28h ; (\r\n.data:000000018000503B db 0F4h ; ô\r\n.data:000000018000503C db 0E7h ; ç\r\n.data:000000018000503D db 8Fh\r\n.data:000000018000503E db 78h ; x\r\n.data:000000018000503F db 4Bh ; K.\r\nNow is there anything important about these bytes ? well yes, if you by chance have read the first part of the\r\nblacklotus analysis you'll know that i referenced an asian's researcher work. Well that researcher was kind enough\r\nto also analyse the dropped bootkit . Please check it\r\nout(https://www.cnblogs.com/DirWang/p/17294545.html#autoid-3-2-1) , so in his analysis he was kind enough to\r\ngive us that info. He points us to\r\nhttps://github.com/Mattiwatti/EfiGuard/blob/master/EfiGuardDxe/PatchWinload.c . there we see a similar line\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 4 of 14\n\nIs there a specific reason behind this , honestly i don't know it's my first time analysing a bootkit . Please do let me\r\nknow or make a pr/pull request to edit this document if you have more experience than i do :) in this area\r\n=============================================================================\r\nCool next, fortune favours us and the pseudo code from ida is simillar with assebmly\r\nso what i guess happens here is normal initialisation of EFI_SYSTEM_TABLE which basically i guess initializes\r\nwhich process to continue the boot process. and than we have the function call PatchBootManager\r\n=============================================================================\r\nPatchBootManager\r\nAnd from pseudo code\r\nColl so first function call we see it does is HandleProtocol. So what the code does it do ? Luckly we stumble\r\nupong this when doing a quick google search (https://tianocore-docs.github.io/edk2-\r\nModuleWriteGuide/draft/5_uefi_drivers/54_communication_between_uefi_drivers.html) and we see that it\r\nretrieve protocols . Cool nothign rlly that can i make sense. Ye i gotcha' fam. So basically this retrives\r\ncommunication informationmethods used by other UEFI drivers. Cool some more digging. we see the second\r\nparameter is\r\nIf we search for that specifc bytes we come across this\r\nso wtf does EFI_LOADED_IMAGE_PROTOCOL_GUID do ? quoting\r\nfrom(https://uefi.org/specs/UEFI/2.10/09_Protocols_EFI_Loaded_Image.html) Can be used on any image\r\nhandle to obtain information about the loaded image. , what type of info ? ```This section defines\r\nEFI_LOADED_IMAGE_PROTOCOL and the EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL.\r\nRespectively, these protocols describe an Image that has been loaded into memory and specifies the device path\r\nused when a PE/COFF image was loaded through the EFI Boot Service LoadImage(). These descriptions include\r\nthe source from which the image was loaded, the current location of the image in memory, the type of memory\r\nallocated for the image, and the parameters passed to the image when it was invoked.````\r\nSo in our case grabs info about the bootkit. Now there's a problem we can't rlly inspect the resut of the function bc\r\nwe have no debug symbols :/ but we can presume. and i tend to presume that the structure(result from previous\r\nfunction call)will be in rbx.\r\nNext we call demangle string\r\nwhich gets us\r\nand than we call\r\n=============================================================================\r\nsub_180002B14\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 5 of 14\n\nand pseudo code\r\nCool so until the if everythin's self explanatory,now what about the if? We see again it does a call with\r\nunk_180005010 as parameters which is an array of bytes again, upon further inspection it looks like this\r\nNow if we inspect the first bytes again and do a quick search we come around this\r\n(https://github.com/theopolis/uefi-firmware-parser/blob/master/uefi_firmware/guids/efiguids_ami.py) more\r\nprecisely this 'EFI_DEVICE_PATH_PROTOCOL_GUID': [0x09576e91, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0,\r\n0xc9, 0x69, 0x72, 0x3b] .\r\nIf we go again on uefi's spec page we see that Can be used on any device handle to obtain generic\r\npath/location information concerning the physical device or logical device. . Coon we also se more like\r\nthis The device path describes the location of the device the handle is for . OK cool and if we scroll\r\njust a little we see a function called _EFI_DEVICE_PATH_PROTOCOL. Ok so to conclude we know this this has\r\nti di with EFI_DEVICE_PATH_PROTOCOL_GUID but our function is of type EFI_BOOT_SERVICES. So is\r\nthere any function in EFI_BOOT_SERVICES which could do something like handling a protocol ? yes there is . If\r\nwe inspect https://www.intel.com/content/dam/doc/product-specification/efi-v1-10-specification.pdf section 4.4\r\nwe see\r\nmore precisely it has a function to which we are familiar(HandleProtocol). Cool\r\nNext we see another function call unkow this time to us. Let's see what arguments it takes, So it take 2,than len of\r\npassed string as unicode , and ptr to a variable\r\nNow if we inspect this in a debugger\r\nwe see a weird thing rcx has a debug string which AllocatePool, which comes after a function call so we conclude\r\nthat this was possible a call to AllocatePool, funny enough if you also inspect the specs you'll see that\r\nboot_services also has a ptr to AllocatePool which only makes our assumption stronger.\r\nCool so if we manage to allocate enough space(the check if \u003e= 0 is to check if we succesed to allocate bc if\r\nEFI_OUT_OF_RESOURCES is implemented as\r\nit's only safe to assume\r\nis used for success allocation)\r\nOne interesting fact is that the buffer after allocating it is not zero but rather it has these bytes in it. If anyone\r\nknows more abut this please make a pr request to edit this document\r\nSo yeah anyway we end up calling memcpy after the call our buffer looks like this\r\nWe than append some bytes to get the buffer to look like this\r\nAnd than call a function called FileDevicePath_call which looks about like this\r\nAnd translates to this\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 6 of 14\n\nCool but this don make no sense if not explained so....\r\nfirst we have a custom implementation of strlen which we won't dissecc cause it's usless :) But here's the result\r\n32 chars from len(of(str)+\"\\x00\" and than the last 4 bytes appended before the function call 0x4FF7F\r\nNext we call what i also used from the asian's research blog post PxepDevicePathInstanceCount, which is simply\r\nstrlen, cause it simply counts each letter and has a counter. as seen here\r\nSo yeah we see pop rbx and after call we see rbx=0x48\r\nwe than call against strlen again on the same string , i guess this is just bc on next line precisly , v6 + v4 * v5;\r\nwe do v4*v5 which is like i guess some way of having unicode strings i guess\r\nAnyway an than we allocate memory again using gEfiBootServices + 64 which we previously enocuntered which\r\nsolved to AllocatePool.\r\nSo here we also see something nice which is\r\nthe fact that here the memory block has the pattern afafafaf in it .\r\nSo what happens next is that we get two buffer which look like this after the main loop executes\r\nAnd truelly speaking we are interested in only the first one because that's what get's returned, so we can conclude\r\nthis simply i guess copies the device path and clear some garbabe from buffer. :))\r\nNow after we finish with this we check to see if the device path in our case is already i guess initialised and free\r\nthe pool if not we return the clearer buffer from the previous mentioned function .\r\nBefore we finish with this function i would like to point another interesting fact , this is how it looks in memory\r\nthe bootservice table :) it looks like according to the specs with the begging header just figured it might be\r\ninteresting to let here for anyone who wanna do feature work and find themselves finding this string\r\nBOOTSERVF in a dump, this is deffno bootservice table\r\n=============================================================================\r\nRight so what happens next ??? well we check to see if we managed to locate the winload.efi file and we load it\r\ninto memory. this is the pseudo code :)\r\nAnd this is how it looks into memory\r\nwhat is rax? rax is a handle to the image :) don't be dumb like me when i first tought that it is a memory zone :)\r\nCool before we head in for some more let me quickly explain wtf is winload.efi. So, with the development of\r\ncomputers, the traditional BIOS boot is outdated, and the security confrontation about UEFI boot has\r\nstarted. From the flow chart below, we can see that MBR and VBR no longer exist in UEFI, but UEFI\r\nitself is responsible for loading bootmgr, which also means safer and faster\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 7 of 14\n\nSo how does a normal windows pc boots ? After BDS, the UEFI firmware code stored in SPI has completed the\r\nwork, then the UEFI firmware boot manager first queries the NVRAM UEFI variable to find the ESP, and finds\r\nthe OS-specific boot manager bootmgfw.efi to call its entry function (DXE driver).\r\nThis function will first call the EfiInitCreateInputParametersEx function, which is mainly used to convert the\r\nEfiEntry parameter into the parameter format expected by bootmgfw.efi.\r\nThe Windows Boot Manager entry point BmMain function is then called.\r\nIn this function, BmFwInitializeBootDirectoryPath is called to initialize the startup application (BootDirectory)\r\npath (\\EFI\\Microsoft\\Boot).\r\nThen BootMgr will read the system boot configuration letter (BCD), if there are multiple boot options, it will call\r\nBmDisplayGetBootMenuStatus to display the boot menu.\r\nThen it will call the BmpLaunchBootEntry function to start the application (winload.efi).\r\nOf course, bootmgfw.efi does more than that, as well as boot policy verification code integrity and initialization of\r\nsecure boot components, so I won’t go into details.\r\nIn the final stage of Windows Boot Manager (BootMgr), the BmpLaunchBootEntry function will select the correct\r\nboot entry according to the previous BCD value. If full volume encryption (BitLocker) is enabled, the system\r\npartition will be decrypted first, and then the control can be transferred to winload.efi.\r\nNext, the BmTransferExecution function is called, the startup options are checked and the execution flow is\r\npassed to the BlImgStartBootApplication function.\r\nThen the BlImgStartBootApplication function will call the ImgFwStartBootApplication function, and finally call\r\nthe ImgArchStartBootApplication function. In it, the memory protection mode of winload.efi will be initialized,\r\nThen call the BlpArchTransferTo64BitApplication function, BlpArchTransferTo64BitApplication calls The\r\nArchpx64TransferTo64BitApplicationAsm function finally hands over control to winload.efi.\r\nThis function will enable the new GDT and IDT, and then completely hand over the control to winload.efi. At this\r\npoint, BootMgr completes its mission and Winload starts to work. -End of quotes stolen from a chinese website\r\nwhich talks about this(please review this for more content https://bbs.kanxue.com/thread-268267.htm )\r\nAnd from there winload.efi does it job which is to load windows and do some more hw work before it hands\r\ncontrol to kernel .\r\nNow after this sort briefing as we were saying\r\nwe further check to see if loading it into memory successeded and than we do a function called\r\nati_analysis_rdtsc_aia_cu_4e1f to which you should be familiar if you have already read the first part of this\r\nanalysis.\r\nNow for the fun lets pretend we fail to analyse that function and we get detected.Let's see how sub_180002A08\r\nlooks like.\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 8 of 14\n\nwe see again gEfiSystemTable + 64 which we actually don't know this time because it's of different type it's not of\r\ntype bootservices this time is of type efisystemtable than memcpy and another 3 function call which we don't\r\nknow now if we run until the loop begins\r\nand if we inspect previous paramets to memcpy\r\nand we inspect the output image of qemu we get\r\nCool so let's make some sense of this ,i'll refear again to the asian's research blogpost cause honestly i'm lost here\r\nSo on his blog he says that the two functions were actually\r\nConOut-\u003eClearScreen(ConOut);\r\nConOut-\u003eOutputString(ConOut, String);\r\nOk but wtf is conOut? well also he says that conout is of type EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL and\r\nthat conout is obtained by ConOut = gEfiSystemTable-\u003eConOut; . ok so what in the code does this mean ??\r\nOk so let's digg in\r\nthe deffinition\r\nand the guid\r\nNow my smart ass forgot to actually capture this in a debugger because first when i anaylsed this i confused the\r\ndata type between efisystemtable and bootservices and i tought this is actually allocatepool.\r\nNow what thoese function do?\r\nWell ClearScreen should be pretty self explanatory and so should OutputString too. How could the researcher\r\ncome to the conclusion that that variable is of type EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL? well probably\r\nhe saw the guid bytes in the debugger.\r\nNow what about the last function ?\r\nwell in his blogpost he says that last function is gEfiBootServices-\u003eStall ? so wtf this this do ? . From uefi specs\r\nThe Stall() function stalls execution on the processor for at least the requested number of\r\nmicroseconds. Execution of the processor is not yielded for the duration of the stall.\r\nSo basically is makes our cpu freze. cool for how long 0x1C9C380 seconds. a shit tone of time if you ask me.\r\nwhich is again pun in an infite loop so yeah we fucked :)))\r\nAnd this is how it looks in a debugger\r\nNow continuing with our main function\r\nif we manage to load the bootmgfrw.efi(bc winload.efi here is the actual windows bootloader) we call\r\nsub_180002538\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 9 of 14\n\n=============================================================================\r\nsub_180002538\r\nFrom a graph perspective\r\nFrom asm perspective\r\nAnything ringing a bell yet ? nah well give it a minute it will sinc it , in the meantime take a lookt at pseudo code\r\npov\r\nwe see some parsing of an exe :) now idk how much it will be the same as the one from previous part(part1) but\r\nlet's see :)\r\nso we compare our in memory version of the binary(bootmgfrw.efi) with classical mz header(0x5A4D), as you\r\ncan see\r\nok next we do another classic check which is if we can find pe header\r\nCool next we call sub_1800024C4() which looks like this\r\nCool so what happens here is that we locate certain values in memory and if we found them we return them.\r\nPlease reffer to sub_180002538.py.py for the emulation.\r\nAnyhow here's sub_180002464\r\nIf we successfully execute sub_1800024C4 we return in the bigger function and follow a few more checks , cool\r\nbeans let's mase some sense of these\r\nCool so we further compare whatever is at rax+0xe with 0x64 hmm cool interesting , inspecting rax+0xe\r\nAny special reason behind this specific check? honestly idk? it might be if you know please make a pull request\r\nand edit this document\r\nwe do some more addition and than a comparison\r\nI wanna stop here for a minute and reference again the previous source of inspiration for this article whenever i\r\ngot lost, so in his blog he renamed the function which compared values to RtlpImageDirectoryEntryToDataEx,\r\nwhich if we search we got no results but there's something close enough to his names and that is\r\nRtlImageDirectoryEntryToData , which basically does this Given the base address of a kernel module and\r\nthe index of an entry in the data directory, RtlImageDirectoryEntryToData() returns the virtual\r\naddress and the size of the directory entry (https://codemachine.com/articles/top_ten_kernel_apis.html) in\r\nour case since we are in an efi/uefi app we can consider that the 50 we see is the size of bytes/mb idk here of our\r\nroot partition in this case and that that address which is in rax is an entry in our directory.\r\nBefore we further proceed there's one more interesting detail to be explained. In his research he converts the\r\noutput of RtlImageDirectoryEntryToData to this structure\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 10 of 14\n\ntypedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {\r\n union {\r\n struct {\r\n DWORD NameOffset : 31;\r\n DWORD NameIsString : 1;\r\n };\r\n DWORD Name;\r\n WORD Id;\r\n };\r\n union {\r\n DWORD OffsetToData;\r\n struct {\r\n DWORD OffsetToDirectory : 31;\r\n DWORD DataIsDirectory : 1;\r\n };\r\n };\r\n } IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;\r\nNow wtf about this structure ?\r\nwell doing a quick search about that structure gets us\r\nhere(http://www.brokenthorn.com/Resources/OSDevPE.html) which tells us that Parsing resources is a bit\r\nmore complex then the other directory types, however. Like the other sections, there is a base\r\nIMAGE_RESOURCE_DIRECTORY structure that can be obtained from the DataDirectory member of the optional\r\nheader: blah blah and also that ```This structure doesnt have much of any interesting fields, except the last\r\nthree.\r\nIf you have worked with Win32 resources, you might know that resources can be idenitified by ID or name. Two\r\nof the members in this structure will let us know the number of these entries, and the total amount of entries\r\n(NumberOfNamedEntries + NumberOfIdEntries), which is useful in looping through all of the entries. As you can\r\nprobably guess, the entries are in the DirectoryEntries array. DirectoryEntries consists of an array of\r\nIMAGE_RESOURCE_DIRECTORY_ENTRY structures, which follow the format:```\r\nso basically this shit is used internally for parsing stuff internally and for us makes sense in the context of the fact\r\nthat we work with a directory which has resources in it, cool.\r\nMore please!\r\nSo up next\r\nwhat dis to is that basically iterate over every resource from directory and checks to see if it's of type string\r\nngl i don't know why he would so if i'm wrong sorry if i'm not cheers!\r\nnext\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 11 of 14\n\nso what happens here is that we add some offsets and end up to what the chinese researcher says it's second\r\nresource table, as you can see\r\nand than we repeat same process to get some offsets\r\nand repeat same process this time we check for type VS_VERSION_INFO\r\nso wtf is VS_VERSION_INFO? well microsoft(https://learn.microsoft.com/en-us/windows/win32/menurc/versioninfo-resource) says that Defines a version-information resource , eg i\r\nbelive is simply says the version of bootmgfrw.ef\r\nand finally if we found VS_VERSION_INFO we repeat same algorithm\r\nthis time with a twist, the twist being that we return the build id :) as we can see\r\nSo as a conclusion wtf happened here actually ? well based on the name the chinese researcher\r\nused(GetPeFileVersionInfo_BuildNumber_) we can conclude that we actauly get build number for bootload as can\r\nbe seen from the first image\r\nwhere here we see the loade bootload in memory\r\nin second image we see\r\nan integer in rcx which could either be build nr or pefileversion\r\nand 3rd image\r\nwhat we could speculate to be build number as ebx will be moved into rax :)\r\nSo as a last note on this function, wow amazing engineering\r\n=============================================================================\r\nNow onto next challenge :) based on the output from previous stage we either set v10 to sub_180001D80 or\r\nsub_180001D48, as seen\r\nand in our case v10=sub_180001D80\r\n=============================================================================\r\nWe than do a strcmp between our bootloade manager and that array of bytes\r\nI wanna stop here for a brief short period of time , as you might have guest it i saw something interesting in the\r\nchineses researcher blog post. he called the array of btyes SigImgArchStartBootApplication. so wtf is\r\nSigImgArchStartBootApplication and to who it belong and why the hack is that array called that way(migos) . So\r\nif we search on google(gulugulu) for SigImgArchStartBootApplication we get nothing. Now give that the current\r\ncontext we use the bootloader manager of windows let's open it in IDA. We go to C:\\Windows\\Boot\\EFI, open the\r\nbinary in ida an search SigImgArchStartBootApplication, nothing. We search for ImgArchStartBootApplication\r\nand we are met with\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 12 of 14\n\nSo ImgArchStartBootApplication .... what the dog doin... !? Well amm...hh I will steal this from @_xeroxz (go\r\nfollow him, wtf you doing if you not following his work....) so basically in an article he says that\r\nbootmgfw.ImgArchStartBootApplication between windows versions 2004-1709 is invoked to start\r\nwinload.efi as we can see also from his image(https://guidedhacking.com/threads/hyper-v-hacking-framework-works-on-every-version-of-windows-10-2004-1511-amd-intel.16251/)\r\nIf that was not clear enougn on an article() we see that ImgArchStartBootApplication to catch the moment when\r\nthe Windows OS loader (winload.efi) is loaded in the memory but still has not been\r\nexecuted (https://rustrepo.com/repo/rusty-bootkit--uefi-bootkit-in-rust)\r\nCool so wtf does strcmp have to do with ImgArchStartBootApplication? well let's take a closer look at ida and we\r\nwill soon be reveal with the answear, if we search in bootloader code for bytes 41 b8 09 we are soon meet with the\r\ncoolprit\r\nAnd in case we match our in memory image bytes of bootloade with the signature of bytes we execute\r\nsub_180002398\r\nAnd surely as can be seen we located the pattern we got returned in eax the memory zone where the bytes are and\r\nwe safely proceed to run sub_180002398\r\n=============================================================================\r\nsub_180002398\r\n\"Assembly perspective\"\r\n\"Pseudo-code perspective\"\r\nSo what the dog doing ? honestly it does some calculation and some additions substractions and nothing rlly\r\nimportant ? why because it's not that interesting . What we interested in is what happens after we return from the\r\nfunction. We see rax\r\nok cool so i still don't get it . Well rax = 0x5eec108 which points to 0x48c48b48 , ok and what ? well i was as\r\nconfused as you were so i returned once again to the chinese blog. So what that researcher describes it happens\r\nhere is this: it goes back to the beginning of the ImgArchStartBootApplication function. But how tf did he come\r\nup with this ? well as mention earlier rax = 0x48c48b48 and if we inspect the booloadermnfr.efi we see\r\nwhich is exactly the same sequence of bytes in 0x5eec108. ok now that's cool :)\r\nPlease reffer to sub_180002398.py to see my failed attempt to emulate this behaviour :)\r\n=============================================================================\r\nCool next ?\r\nSo what happens next is RaiseTPL . ok so what this do ? Raises the priority of the currently executing task and\r\nreturns its previous priority level. In our case it will be run as highest execution privillages.\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 13 of 14\n\nNext we call what i called patch_something which looks like this\r\nSo from statical analysis we can see this is what it's known as hooking. :) so basically it patches the bytes of\r\nImgArchStartBootApplication to point to sub_180001D80 and saves original function of\r\nImgArchStartBootApplication to byte_180015C78\r\nas as we can see it change to exactly sub_180001D80\r\nnext we reset the privilleges and from there we hand the control to boomgrfw.efi :)\r\nSo this officially marks the first half of the analysis done :) next part we will learn how to further debug\r\nsub_180001D80 and boomgrfw.efi(in our case winload.efi) So please sit thight till i learn how to prepare the\r\nenvironment for the second part of the analysis\r\n=============================================================================\r\nNow for the second half of the analysis.... How to do we debug boomgrfw.efi ?\r\nLast updated 2 years ago\r\nSource: https://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nhttps://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/\r\nPage 14 of 14",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://kn0s-organization.gitbook.io/blacklotus-analysis-stage2-bootkit-rootkit-stage/"
	],
	"report_names": [
		"blacklotus-analysis-stage2-bootkit-rootkit-stage"
	],
	"threat_actors": [],
	"ts_created_at": 1775439127,
	"ts_updated_at": 1775826722,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/7855b159d34a19521e0b8ea0af2fa544fa1ac667.pdf",
		"text": "https://archive.orkl.eu/7855b159d34a19521e0b8ea0af2fa544fa1ac667.txt",
		"img": "https://archive.orkl.eu/7855b159d34a19521e0b8ea0af2fa544fa1ac667.jpg"
	}
}