Hesperbot DGA : Everything is Dynamically generated using GA
by
, 11-10-2014 at 12:01 PM (0 Views)
Hesperbot DGA : Everything is Dynamically generated using GA
Our next contender for DGA series is Hesperbot. It generates all strings/object-names dynamically using various "Generation Algorithms"
similar to DGA. Though its DGA differs from NGA (Name generation algorithm) used for name generation for objects like filenames, foldernames,
mutexes etc.
But both DGA & NGA utilises same seed generator. Hesperbot's DGA is free from date/time and generates same series of domain names
for any salt/magic-number. The salt/magic-number may differ across different samples. Also it generates TLD
dynamically all this makes this DGA non-spottable & unconventional.
So where should we start now? Its bit difficult to track the DGA in action as it may either start in legitimate
Explorer.exe otherwise in child process. Hesperbot starts a child named "explorer.exe" and also injects same code inside legitimate
"Explorer.exe" & terminates original parent process. We can debug both explorers or initially only child explorer.exe as you wish.
We are again only interested in DGA and not going to discus how the the sample unpacks/injects the code etc.
From api tracing we discovered that "RtlFreeHeap" is called several times. We set a breakpoint on "RtlFreeHeap".
It pops several times including the generation of mutex which starts like "lock_....." like that.
Let the RtlFreeHeap return and we check the executing code trail. One specific call which looks interestign and is made across several
other subroutines as well is for a subroutine at 0x0009FC4B which is
It appears like seed generator as it generates long binary string.Code:0009FC4B 55 PUSH EBP 0009FC4C 8BEC MOV EBP,ESP 0009FC4E 83EC 10 SUB ESP,10 0009FC51 837D 08 00 CMP DWORD PTR SS:[EBP+8],0 0009FC55 57 PUSH EDI 0009FC56 8BF9 MOV EDI,ECX 0009FC58 C745 F4 810349B0 MOV DWORD PTR SS:[EBP-C],B0490381 0009FC5F B9 F988E254 MOV ECX,54E288F9 0009FC64 C745 FC 7C683106 MOV DWORD PTR SS:[EBP-4],631687C 0009FC6B 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX 0009FC6E 74 53 JE SHORT 0009FCC3 0009FC70 53 PUSH EBX 0009FC71 56 PUSH ESI 0009FC72 EB 03 JMP SHORT 0009FC77 0009FC74 8B4D F0 MOV ECX,DWORD PTR SS:[EBP-10] 0009FC77 8BC7 MOV EAX,EDI 0009FC79 C1E0 0B SHL EAX,0B 0009FC7C 33C7 XOR EAX,EDI 0009FC7E 8B7D F4 MOV EDI,DWORD PTR SS:[EBP-C] 0009FC81 894D F4 MOV DWORD PTR SS:[EBP-C],ECX 0009FC84 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4] 0009FC87 894D F0 MOV DWORD PTR SS:[EBP-10],ECX 0009FC8A C1E9 0B SHR ECX,0B 0009FC8D 33C8 XOR ECX,EAX 0009FC8F C1E9 08 SHR ECX,8 0009FC92 33C8 XOR ECX,EAX 0009FC94 314D FC XOR DWORD PTR SS:[EBP-4],ECX 0009FC97 6A 04 PUSH 4 0009FC99 5E POP ESI 0009FC9A 3975 08 CMP DWORD PTR SS:[EBP+8],ESI 0009FC9D 73 03 JNB SHORT 0009FCA2 0009FC9F 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8] 0009FCA2 85F6 TEST ESI,ESI 0009FCA4 74 13 JE SHORT 0009FCB9 0009FCA6 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8] 0009FCA9 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4] 0009FCAC 2BC1 SUB EAX,ECX 0009FCAE 8BD6 MOV EDX,ESI 0009FCB0 8A1C08 MOV BL,BYTE PTR DS:[EAX+ECX] 0009FCB3 8819 MOV BYTE PTR DS:[ECX],BL 0009FCB5 41 INC ECX 0009FCB6 4A DEC EDX 0009FCB7 ^75 F7 JNZ SHORT 0009FCB0 0009FCB9 0175 F8 ADD DWORD PTR SS:[EBP-8],ESI 0009FCBC 2975 08 SUB DWORD PTR SS:[EBP+8],ESI 0009FCBF ^75 B3 JNZ SHORT 0009FC74 0009FCC1 5E POP ESI 0009FCC2 5B POP EBX 0009FCC3 5F POP EDI 0009FCC4 C9 LEAVE 0009FCC5 C3 RETN
Let us check which subroutines are calling it? A reference check returns following results :
Its not easy to land in Hesperbot's DGA directly. Let us one-by-one check all these routinesCode:References in 00090000..000A7FFF to 0009FC4B Address Disassembly Comment 000966D3 CALL 0009FC4B 0009ACBB CALL 0009FC4B 0009ADA1 CALL 0009FC4B 0009CE25 CALL 0009FC4B 0009FC4B PUSH EBP (Initial CPU selection) 000A083B CALL 0009FC4B
and set breakpoints on them accordingly in each fresh execution. Also Give network access to your VM after
you set BP on those routines.
I would suggest to search for similar codeblock across all memory blocks and set breakpoints in references in
all blocks.
Most of the referencing routines are generating other stuff, but only interesting routine that has reference to this seed generator
is one that is calling it from
Let us check the routine and its logical execution flow:Code:0009CE25 CALL 0009FC4B
Code:0009CDF4 55 PUSH EBP 0009CDF5 8BEC MOV EBP,ESP 0009CDF7 8B06 MOV EAX,DWORD PTR DS:[ESI] 0009CDF9 83EC 18 SUB ESP,18 0009CDFC 57 PUSH EDI 0009CDFD 85C0 TEST EAX,EAX 0009CDFF 75 07 JNZ SHORT 0009CE08 0009CE01 8D7E 10 LEA EDI,DWORD PTR DS:[ESI+10] 0009CE04 6A 1A PUSH 1A 0009CE06 EB 4B JMP SHORT 0009CE53 0009CE08 50 PUSH EAX 0009CE09 E8 BFFFFFFF CALL 0009CDCD ; Salt generator ; This section determines the length of domain name 0009CE0E 59 POP ECX 0009CE0F 6A 19 PUSH 19 0009CE11 5F POP EDI 0009CE12 33D2 XOR EDX,EDX 0009CE14 8BC8 MOV ECX,EAX 0009CE16 F7F7 DIV EDI 0009CE18 6A 08 PUSH 8 0009CE1A 5F POP EDI 0009CE1B 3BD7 CMP EDX,EDI 0009CE1D 76 02 JBE SHORT 0009CE21 0009CE1F 8BFA MOV EDI,EDX 0009CE21 57 PUSH EDI ;----------- 0009CE22 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18] 0009CE25 E8 212E0000 CALL 0009FC4B ; Call to seed generator 0009CE2A 59 POP ECX 0009CE2B 33C9 XOR ECX,ECX 0009CE2D 85FF TEST EDI,EDI 0009CE2F 74 1C JE SHORT 0009CE4D 0009CE31 53 PUSH EBX 0009CE32 0FB6440D E8 MOVZX EAX,BYTE PTR SS:[EBP+ECX-18] ; The seed 0009CE37 99 CDQ 0009CE38 6A 1A PUSH 1A ; 0x1A == 26 == number of alfabets 0009CE3A 5B POP EBX 0009CE3B F7FB IDIV EBX 0009CE3D 41 INC ECX 0009CE3E 8A82 783D0A00 MOV AL,BYTE PTR DS:[EDX+A3D78] ; "abcdefghijklmnopqrstuvwxyz" 0009CE44 88440E 0F MOV BYTE PTR DS:[ESI+ECX+F],AL ; Byte Appended to domain name 0009CE48 3BCF CMP ECX,EDI 0009CE4A ^72 E6 JB SHORT 0009CE32 0009CE4C 5B POP EBX 0009CE4D 8D7C31 10 LEA EDI,DWORD PTR DS:[ECX+ESI+10] 0009CE51 6A 19 PUSH 19 0009CE53 59 POP ECX 0009CE54 E8 17A8FFFF CALL 00097670 ; Appends Top-Level-Domain i.e. ".com" 0009CE59 33C0 XOR EAX,EAX 0009CE5B 40 INC EAX 0009CE5C 5F POP EDI 0009CE5D C9 LEAVE 0009CE5E C3 RETN 0009CE5F 56 PUSH ESI 0009CE60 57 PUSH EDI 0009CE61 6A 2F PUSH 2F 0009CE63 8BF0 MOV ESI,EAX 0009CE65 33FF XOR EDI,EDI 0009CE67 58 POP EAX 0009CE68 48 DEC EAX 0009CE69 C60430 00 MOV BYTE PTR DS:[EAX+ESI],0 ; Memset 0009CE6D ^75 F9 JNZ SHORT 0009CE68 0009CE6F 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C] 0009CE73 8906 MOV DWORD PTR DS:[ESI],EAX 0009CE75 B8 BB010000 MOV EAX,1BB 0009CE7A 66:8946 2D MOV WORD PTR DS:[ESI+2D],AX 0009CE7E E8 71FFFFFF CALL 0009CDF4 ; Call to Domain Name Generator 0009CE83 85C0 TEST EAX,EAX 0009CE85 74 03 JE SHORT 0009CE8A 0009CE87 33FF XOR EDI,EDI 0009CE89 47 INC EDI 0009CE8A 8BC7 MOV EAX,EDI 0009CE8C 5F POP EDI 0009CE8D 5E POP ESI 0009CE8E C3 RETN
Code:; Salt generator : 0009CDCD 33C9 XOR ECX,ECX 0009CDCF B8 8F897827 MOV EAX,2778898F ; 0x2778898F is Magic number. It may differ in some samples. 0009CDD4 394C24 04 CMP DWORD PTR SS:[ESP+4],ECX 0009CDD8 76 19 JBE SHORT 0009CDF3 0009CDDA 8BD1 MOV EDX,ECX 0009CDDC C1E2 09 SHL EDX,9 0009CDDF 0FAFD0 IMUL EDX,EAX 0009CDE2 81F2 3D44BD4E XOR EDX,4EBD443D 0009CDE8 03D1 ADD EDX,ECX 0009CDEA 03C2 ADD EAX,EDX 0009CDEC 41 INC ECX 0009CDED 3B4C24 04 CMP ECX,DWORD PTR SS:[ESP+4] 0009CDF1 ^72 E7 JB SHORT 0009CDDA 0009CDF3 C3 RETThe reversed Hesperbot DGA in python is as follow :Code:TLD generator : 00097670 56 PUSH ESI 00097671 33F6 XOR ESI,ESI 00097673 3934CD 04540A00 CMP DWORD PTR DS:[ECX*8+A5404],ESI 0009767A 76 28 JBE SHORT 000976A4 0009767C 53 PUSH EBX 0009767D 33D2 XOR EDX,EDX 0009767F 6A 29 PUSH 29 00097681 8BC6 MOV EAX,ESI 00097683 5B POP EBX 00097684 F7F3 DIV EBX 00097686 8B04CD 00540A00 MOV EAX,DWORD PTR DS:[ECX*8+A5400] 0009768D 8A92 8C500A00 MOV DL,BYTE PTR DS:[EDX+A508C] 00097693 321430 XOR DL,BYTE PTR DS:[EAX+ESI] 00097696 88143E MOV BYTE PTR DS:[ESI+EDI],DL 00097699 46 INC ESI 0009769A 3B34CD 04540A00 CMP ESI,DWORD PTR DS:[ECX*8+A5404] 000976A1 ^72 DA JB SHORT 0009767D 000976A3 5B POP EBX 000976A4 C6043E 00 MOV BYTE PTR DS:[ESI+EDI],0 000976A8 5E POP ESI 000976A9 C3 RETN
Code:''' Developer : Garage4Hackers Greets : nightrover, b0nd, FB1H2S, "vinnu", l0rdDeathStorm and all g4h team ''' import time, os family = "Hesperbot" utility = family+"-DGA" def initSeed(maxnum, salt): ecx = 0x54E288F9 stack = [0xB0490381, # ebp-c 0x0010F200, 0x0631687C, # ebp-4 ecx # ebp-0x10 ] edi = salt rindex = maxnum i = maxnum buf = '' while i > 0 : ecx = stack[3] eax = edi print "[0] eax : %08x ecx : %08x edi : %08x"% (eax, ecx, edi) eax = (eax << 0x0B) & 0xFFFFFFFF print "[1] eax : %08x ecx : %08x edi : %08x"% (eax, ecx, edi) eax = eax ^ edi print "[2] eax : %08x ecx : %08x edi : %08x"% (eax, ecx, edi) edi = stack[0] stack[0] = ecx print "[3] eax : %08x ecx : %08x edi : %08x"% (eax, ecx, edi) ecx = stack[2] print "[4] eax : %08x ecx : %08x edi : %08x"% (eax, ecx, edi) stack[3] = ecx #stack.append(ecx) ecx = (ecx >> 0x0B) & 0xFFFFFFFF ecx = ecx ^ eax ecx = (ecx >> 0x08) & 0xFFFFFFFF ecx = ecx ^ eax print "eax : %08x ecx : %08x"% (eax, ecx) stack[2] = stack[2] ^ ecx print "stack[2] : %08x"% (stack[2]) esi = 4 if rindex <= esi : esi = rindex print "esi : %08x"% (esi) print "stack[2] : %x" % (stack[2]) tmp = "%08x" % (stack[2]) tmp = tmp.decode("hex") buf += tmp[::-1] print "tmp[::-1] : %s" % (tmp[::-1]).encode("hex") i -= esi #time.sleep(10) print "buf : "+buf.encode("hex") #time.sleep(10) return buf def addSalt(iteration): i = 0; magic = 0x2778898F # May differ across different samples #magic = 0x2461156F if iteration > 0: for i in range(iteration): magic = (magic + ( i + ((magic * (i << 9 & 0xffffffff) & 0xffffffff) ^ 0x4EBD443D) & 0xffffffff) & 0xffffffff) & 0xffffffff return magic def generateDomain(domlen, seed): alphabets = "abcdefghijklmnopqrstuvwxyz" domain = "" if domlen > 0: for j in range(domlen): index = ord(seed[j]) % 0x1A domain += alphabets[index] domain += ".com" print "domain : "+domain return domain def initDGA() : maxnum = 0x40 # 0x01BB domains = [] for i in range (maxnum): magic = addSalt(i) edi = 0x19 edx = 0 eax = magic / edi edx = magic % edi edi = 8 if edx > edi : edi = edx seed = initSeed(edi, magic) domain = generateDomain(edi, seed) domains.append(domain) return domains def init() : print "[+] "+utility+" : initiated" domains = initDGA() fp = open("hesperdomains.log", "w") i = 0 for domain in domains : if i == 0 : i += 1 continue line = "[%d] %s\n" % (i, domain) fp.write(line) i += 1 fp.close() init()