Tutorial: Reverse Engineering GameoverZeus DGA code
by
, 08-29-2014 at 06:23 PM (704 Views)
DGA : Is it Game Over for GameoverZeus DGA
GameoverZeus was brought down and it reincarnated again. The Gameover Zeus is a very authentic contender in our DGA series. So let us analyse it and try to reverse its DGA just like we did in case of PushDO in last article.
http://www.garage4hackers.com/entry.php?b=3080
We got lot of request whether we could have a tutorial on reverse engineering DGA codes. So in this series we would have a tutorial on how to Analyze an Gameover Zeus and its DGA code.
Several researchers have already dedicated their precious efforts in documenting its anti-debug/VM behaviour.
Reverse Engineering GameoverZeus DGA code Tutorial.
Step 1:
Put the sample in %temp%\anyname\filename.exe . Now kill the vmtoolsd.exe and double click the filename.exe.
The file.exe will start another child process in my case it is muolax.exe. attach debugger to it.
Now From where should we start? The obvious answers are two points:
1. Where DGA starts
2. Where DGA domains are used up
The DGA mostly starts with any api returning time and DGA returns its final product to network/socket handling
apis which resolve the domain names mostly gethostbyname, getaddrinfo etc.
A search for intermodular api references renders us with 3 calls to "GetSystemTime". The call at :
Looks promising as some arithmatic is going on with 0x3E8.Code:00430A9D FF15 C4C24300 CALL DWORD PTR DS:[43C2C4] ; kernel32.GetSystemTime
After call to GetSystemTime we have a call to 0042F08D.Code:00430A77 ^72 CE JB SHORT muolax.00430A47 00430A79 FF15 04C34300 CALL DWORD PTR DS:[43C304] ; kernel32.GetTickCount 00430A7F 8BF8 MOV EDI,EAX 00430A81 85F6 TEST ESI,ESI 00430A83 74 14 JE SHORT muolax.00430A99 00430A85 B8 E8030000 MOV EAX,3E8 00430A8A 50 PUSH EAX 00430A8B 56 PUSH ESI 00430A8C FF15 BCC24300 CALL DWORD PTR DS:[43C2BC] ; kernel32.WaitForSingleObject 00430A92 3D 02010000 CMP EAX,102 00430A97 75 40 JNZ SHORT muolax.00430AD9 00430A99 8D45 F0 LEA EAX,DWORD PTR SS:[EBP-10] 00430A9C 50 PUSH EAX ; this is what we were finding: 00430A9D FF15 C4C24300 CALL DWORD PTR DS:[43C2C4] ; kernel32.GetSystemTime 00430AA3 33D2 XOR EDX,EDX 00430AA5 B9 E8030000 MOV ECX,3E8 00430AAA 8BC7 MOV EAX,EDI 00430AAC F7F1 DIV ECX 00430AAE 8D4D C8 LEA ECX,DWORD PTR SS:[EBP-38] 00430AB1 52 PUSH EDX 00430AB2 8D55 F0 LEA EDX,DWORD PTR SS:[EBP-10] 00430AB5 E8 D3E5FFFF CALL muolax.0042F08D 00430ABA 47 INC EDI 00430ABB 84C0 TEST AL,AL 00430ABD 74 11 JE SHORT muolax.00430AD0 00430ABF 56 PUSH ESI 00430AC0 FF75 08 PUSH DWORD PTR SS:[EBP+8] 00430AC3 8D45 C8 LEA EAX,DWORD PTR SS:[EBP-38] 00430AC6 50 PUSH EAX 00430AC7 E8 26FEFFFF CALL muolax.004308F2 00430ACC 84C0 TEST AL,AL 00430ACE 75 0D JNZ SHORT muolax.00430ADD 00430AD0 43 INC EBX 00430AD1 81FB F4010000 CMP EBX,1F4 00430AD7 ^72 A8 JB SHORT muolax.00430A81 00430AD9 32C0 XOR AL,AL 00430ADB EB 13 JMP SHORT muolax.00430AF0 00430ADD 8D4D C8 LEA ECX,DWORD PTR SS:[EBP-38] 00430AE0 EB 07 JMP SHORT muolax.00430AE9 00430AE2 8B0CBD A8614000 MOV ECX,DWORD PTR DS:[EDI*4+4061A8] 00430AE9 E8 1F05FFFF CALL muolax.0042100D 00430AEE B0 01 MOV AL,1 00430AF0 5F POP EDI 00430AF1 5E POP ESI 00430AF2 5B POP EBX 00430AF3 8BE5 MOV ESP,EBP 00430AF5 5D POP EBP 00430AF6 C2 0800 RETN 8
The interesting thing about this call is that if we search for words "com", "org" & "biz" in memory,
debugger will end up inside this subroutine's code, it confirms that we are on right track.
The there are several calls to 0042FE3D. This is hashing routine. The subsequent calls to this subroutineCode:0042F08D 55 PUSH EBP 0042F08E 8BEC MOV EBP,ESP 0042F090 83EC 30 SUB ESP,30 0042F093 53 PUSH EBX 0042F094 56 PUSH ESI 0042F095 57 PUSH EDI 0042F096 8BF1 MOV ESI,ECX 0042F098 8BFA MOV EDI,EDX 0042F09A 6A 00 PUSH 0 0042F09C 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-1C] 0042F09F E8 1F0D0000 CALL muolax.0042FDC3 0042F0A4 6A 04 PUSH 4 0042F0A6 5B POP EBX 0042F0A7 53 PUSH EBX 0042F0A8 8D45 08 LEA EAX,DWORD PTR SS:[EBP+8] 0042F0AB C745 F4 01051935 MOV DWORD PTR SS:[EBP-C],35190501 0042F0B2 50 PUSH EAX 0042F0B3 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-1C] 0042F0B6 E8 820D0000 CALL muolax.0042FE3D 0042F0BB 84C0 TEST AL,AL 0042F0BD 0F84 05010000 JE muolax.0042F1C8 0042F0C3 6A 02 PUSH 2 0042F0C5 57 PUSH EDI 0042F0C6 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-1C] 0042F0C9 E8 6F0D0000 CALL muolax.0042FE3D 0042F0CE 84C0 TEST AL,AL 0042F0D0 0F84 F2000000 JE muolax.0042F1C8 0042F0D6 53 PUSH EBX 0042F0D7 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C] 0042F0DA 50 PUSH EAX 0042F0DB 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-1C] 0042F0DE E8 5A0D0000 CALL muolax.0042FE3D 0042F0E3 84C0 TEST AL,AL 0042F0E5 0F84 DD000000 JE muolax.0042F1C8 0042F0EB 6A 02 PUSH 2 0042F0ED 8D47 02 LEA EAX,DWORD PTR DS:[EDI+2] 0042F0F0 50 PUSH EAX 0042F0F1 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-1C] 0042F0F4 E8 440D0000 CALL muolax.0042FE3D 0042F0F9 84C0 TEST AL,AL 0042F0FB 0F84 C7000000 JE muolax.0042F1C8 0042F101 53 PUSH EBX 0042F102 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C] 0042F105 50 PUSH EAX 0042F106 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-1C] 0042F109 E8 2F0D0000 CALL muolax.0042FE3D 0042F10E 84C0 TEST AL,AL 0042F110 0F84 B2000000 JE muolax.0042F1C8 0042F116 6A 02 PUSH 2 0042F118 8D47 06 LEA EAX,DWORD PTR DS:[EDI+6] 0042F11B 50 PUSH EAX 0042F11C 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-1C] 0042F11F E8 190D0000 CALL muolax.0042FE3D 0042F124 84C0 TEST AL,AL 0042F126 0F84 9C000000 JE muolax.0042F1C8 0042F12C 53 PUSH EBX 0042F12D 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C] 0042F130 50 PUSH EAX 0042F131 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-1C] 0042F134 E8 040D0000 CALL muolax.0042FE3D 0042F139 84C0 TEST AL,AL 0042F13B 0F84 87000000 JE muolax.0042F1C8 0042F141 51 PUSH ECX 0042F142 8D45 D4 LEA EAX,DWORD PTR SS:[EBP-2C] 0042F145 50 PUSH EAX 0042F146 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-1C] 0042F149 E8 960D0000 CALL muolax.0042FEE4 0042F14E 84C0 TEST AL,AL 0042F150 74 76 JE SHORT muolax.0042F1C8 0042F152 33DB XOR EBX,EBX 0042F154 32C0 XOR AL,AL 0042F156 8845 FB MOV BYTE PTR SS:[EBP-5],AL 0042F159 0FB6C0 MOVZX EAX,AL 0042F15C 8D1433 LEA EDX,DWORD PTR DS:[EBX+ESI] 0042F15F 6A 08 PUSH 8 0042F161 8B4C05 D4 MOV ECX,DWORD PTR SS:[EBP+EAX-2C] 0042F165 E8 73000000 CALL muolax.0042F1DD 0042F16A 85C0 TEST EAX,EAX 0042F16C 78 5A JS SHORT muolax.0042F1C8 0042F16E 03D8 ADD EBX,EAX 0042F170 8A45 FB MOV AL,BYTE PTR SS:[EBP-5] 0042F173 04 04 ADD AL,4 0042F175 8845 FB MOV BYTE PTR SS:[EBP-5],AL 0042F178 3C 10 CMP AL,10 0042F17A ^72 DD JB SHORT muolax.0042F159 0042F17C C60433 2E MOV BYTE PTR DS:[EBX+ESI],2E 0042F180 43 INC EBX 0042F181 F645 08 03 TEST BYTE PTR SS:[EBP+8],3 0042F185 75 0C JNZ SHORT muolax.0042F193 0042F187 C70433 636F6D00 MOV DWORD PTR DS:[EBX+ESI],6D6F63 0042F18E 83C3 03 ADD EBX,3 0042F191 EB 2F JMP SHORT muolax.0042F1C2 0042F193 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] 0042F196 33D2 XOR EDX,EDX 0042F198 6A 03 PUSH 3 0042F19A 59 POP ECX 0042F19B F7F1 DIV ECX 0042F19D 85D2 TEST EDX,EDX 0042F19F 75 09 JNZ SHORT muolax.0042F1AA 0042F1A1 C70433 6F726700 MOV DWORD PTR DS:[EBX+ESI],67726F 0042F1A8 EB 16 JMP SHORT muolax.0042F1C0 0042F1AA F645 08 01 TEST BYTE PTR SS:[EBP+8],1 0042F1AE 75 09 JNZ SHORT muolax.0042F1B9 0042F1B0 C70433 62697A00 MOV DWORD PTR DS:[EBX+ESI],7A6962 0042F1B7 EB 07 JMP SHORT muolax.0042F1C0 0042F1B9 C70433 6E657400 MOV DWORD PTR DS:[EBX+ESI],74656E 0042F1C0 03D9 ADD EBX,ECX 0042F1C2 C60433 00 MOV BYTE PTR DS:[EBX+ESI],0 0042F1C6 EB 02 JMP SHORT muolax.0042F1CA 0042F1C8 32DB XOR BL,BL 0042F1CA 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-1C] 0042F1CD E8 3A0C0000 CALL muolax.0042FE0C 0042F1D2 5F POP EDI 0042F1D3 5E POP ESI 0042F1D4 8AC3 MOV AL,BL 0042F1D6 5B POP EBX 0042F1D7 8BE5 MOV ESP,EBP 0042F1D9 5D POP EBP 0042F1DA C2 0400 RETN 4
adds year, month, day, 35190501 (salt), and the nonce(generated from 0x3E8 and subsequent iterations)
The correct sequence is :
1. Nonce :
The EDX has nonce/salt. It is added to MD5 hash object.Code:00430A9D FF15 C4C24300 CALL DWORD PTR DS:[43C2C4] ; kernel32.GetSystemTime 00430AA3 33D2 XOR EDX,EDX 00430AA5 B9 E8030000 MOV ECX,3E8 00430AAA 8BC7 MOV EAX,EDI ; EDI is teh counter/iterator 00430AAC F7F1 DIV ECX 00430AAE 8D4D C8 LEA ECX,DWORD PTR SS:[EBP-38] 00430AB1 52 PUSH EDX ; EDX has nonce 00430AB2 8D55 F0 LEA EDX,DWORD PTR SS:[EBP-10] 00430AB5 E8 D3E5FFFF CALL muolax.0042F08D 00430ABA 47 INC EDI ; counter increment : Nonce will be incremented
2. Year is added to MD5 hash object
3. 35190501 (salt)
4. Month
5. 35190501 (Salt)
6. Day
7. 35190501 (Salt)
Generate MD5 hash. After generating MD5 hash a call to 0042F1DD is made at
The subroutine 0042F1DD do arithmatic+logical operations on 8 byte stringlets of MD5 has in 4 separate iterations :Code:0042F165 E8 73000000 CALL muolax.0042F1DD
Finally after creation of domain names, the TLD is attached as inCode:0042F1DD 53 PUSH EBX 0042F1DE 55 PUSH EBP 0042F1DF 8B6C24 0C MOV EBP,DWORD PTR SS:[ESP+C] 0042F1E3 56 PUSH ESI 0042F1E4 57 PUSH EDI 0042F1E5 8BFA MOV EDI,EDX 0042F1E7 4D DEC EBP 0042F1E8 03EF ADD EBP,EDI 0042F1EA 8BF7 MOV ESI,EDI 0042F1EC 3BF5 CMP ESI,EBP 0042F1EE 73 41 JNB SHORT muolax.0042F231 0042F1F0 8BC1 MOV EAX,ECX 0042F1F2 33D2 XOR EDX,EDX 0042F1F4 6A 24 PUSH 24 0042F1F6 59 POP ECX 0042F1F7 F7F1 DIV ECX 0042F1F9 894424 14 MOV DWORD PTR SS:[ESP+14],EAX 0042F1FD 80FA 09 CMP DL,9 0042F200 8D42 30 LEA EAX,DWORD PTR DS:[EDX+30] 0042F203 8D5A 57 LEA EBX,DWORD PTR DS:[EDX+57] 0042F206 0FB6C8 MOVZX ECX,AL 0042F209 0FB6C3 MOVZX EAX,BL 0042F20C 0F47C8 CMOVA ECX,EAX 0042F20F 880E MOV BYTE PTR DS:[ESI],CL 0042F211 46 INC ESI 0042F212 8B4C24 14 MOV ECX,DWORD PTR SS:[ESP+14] 0042F216 85C9 TEST ECX,ECX 0042F218 ^75 D2 JNZ SHORT muolax.0042F1EC 0042F21A 8BC6 MOV EAX,ESI 0042F21C 880E MOV BYTE PTR DS:[ESI],CL 0042F21E 2BC7 SUB EAX,EDI 0042F220 4E DEC ESI 0042F221 8A0F MOV CL,BYTE PTR DS:[EDI] 0042F223 8A16 MOV DL,BYTE PTR DS:[ESI] 0042F225 880E MOV BYTE PTR DS:[ESI],CL 0042F227 4E DEC ESI 0042F228 8817 MOV BYTE PTR DS:[EDI],DL 0042F22A 47 INC EDI 0042F22B 3BFE CMP EDI,ESI 0042F22D ^72 F2 JB SHORT muolax.0042F221 0042F22F EB 02 JMP SHORT muolax.0042F233 0042F231 33C0 XOR EAX,EAX 0042F233 5F POP EDI 0042F234 5E POP ESI 0042F235 5D POP EBP 0042F236 5B POP EBX 0042F237 C2 0400 RETN 4
following code of subroutine 0042F08D :
The TLD are com, org, biz and net.Code:MOV DWORD PTR DS:[EBX+ESI],67726F 0042F17C C60433 2E MOV BYTE PTR DS:[EBX+ESI],2E ; "." 0042F180 43 INC EBX 0042F181 F645 08 03 TEST BYTE PTR SS:[EBP+8],3 0042F185 75 0C JNZ SHORT muolax.0042F193 0042F187 C70433 636F6D00 MOV DWORD PTR DS:[EBX+ESI],6D6F63 ; "com" 0042F18E 83C3 03 ADD EBX,3 0042F191 EB 2F JMP SHORT muolax.0042F1C2 0042F193 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] 0042F196 33D2 XOR EDX,EDX 0042F198 6A 03 PUSH 3 0042F19A 59 POP ECX 0042F19B F7F1 DIV ECX 0042F19D 85D2 TEST EDX,EDX 0042F19F 75 09 JNZ SHORT muolax.0042F1AA 0042F1A1 C70433 6F726700 MOV DWORD PTR DS:[EBX+ESI],67726F ; "org" 0042F1A8 EB 16 JMP SHORT muolax.0042F1C0 0042F1AA F645 08 01 TEST BYTE PTR SS:[EBP+8],1 0042F1AE 75 09 JNZ SHORT muolax.0042F1B9 0042F1B0 C70433 62697A00 MOV DWORD PTR DS:[EBX+ESI],7A6962 ; "biz" 0042F1B7 EB 07 JMP SHORT muolax.0042F1C0 0042F1B9 C70433 6E657400 MOV DWORD PTR DS:[EBX+ESI],74656E ; "net"
The following is the python code for GameoverZeus DGA :
Sample hash for practicing : 3ff49706e78067613aa1dcf0174968963b17f15e9a6bc54396 a9f233d382d0e6Code:''' Developer : Garage4Hackers Greets : b0nd, FB1H2S, vinnu, l0rdDeathStorm, nightrover and all g4h team ''' import os, datetime, time, hashlib, socket family = "GameoverZeus" utility = family+"-DGA" os.system("title "+utility) def hasher(data, algorithm="md5"): h = hashlib.new(algorithm) h.update(data) return h.hexdigest() def getDate(): dt = str(datetime.datetime.now()).split(' ')[0] dstash = dt.split('-') dd = dstash[2] mm = dstash[1] yyyy = dstash[0] return int(dd),int(mm),int(yyyy) def seeder(index, salt): ############ edi = salt+index edx = 0 ecx = 0x03E8 eax = edi edx = eax % ecx eax = eax / ecx print "eax : %x edx : %x salt : %x" % (eax, edx, salt) day, month, year = getDate() h = hashlib.new("md5") dx = ("%08x"%socket.htonl(edx)).decode("hex") print "\tedx : "+dx.encode("hex") h.update(dx) y = ("%x"%socket.htons(year)).decode("hex") print "\tyear : "+y.encode("hex") h.update(y) s = ("%08x"%socket.htonl(salt)).decode("hex") print "\tsalt : "+s.encode("hex") h.update(s) m = ("%04x"%socket.htons(month)).decode("hex") print "\tmonth : "+m.encode("hex") h.update(m) print "\tsalt : "+s.encode("hex") h.update(s) d = ("%x"%socket.htons(day)).decode("hex") print "\tday : "+d.encode("hex") h.update(d) print "\tsalt : "+s.encode("hex") h.update(s) seed = h.hexdigest() return seed, edx def generateDomain(hashlet): print "Generating domain" result = [] print "Hashlet : %x" % hashlet #0042fef6: ########## ecx = hashlet ########## cl = 0 dl = 0 bl = 0 eax = 0 ebx = 0 edx = 0 esi = len(result) edi = 0 while (ecx & 0xFFFFFFFF) : eax = ecx edx = 0 ecx = 0x24 edx = eax % ecx eax = eax/ecx esp14 = eax dl = edx & 0xFF #print "eax: %x ecx : %x edx : %x ebx : %x dl : %x" % (eax,ecx,edx,ebx, dl) eax = edx+0x30 ebx = edx+0x57 al = eax & 0xFF bl = ebx & 0xFF ecx = al eax = bl if dl > 9 : ecx = eax cl = ecx & 0xFF result.append(chr(cl)) ecx = esp14 #time.sleep(1) esi = len(result) eax = esi print "result : %s, esi : %x cl %x" %( ''.join(result), esi, cl) result[esi-1]= chr(cl) eax = eax-edi esi -= 1 while edi < esi : cl = result[edi] dl = result[esi] print "\tesi: %x edi : %x cl : %s dl : %s result :%s" % (esi,edi,cl, dl, ''.join(result)) result[esi] = cl esi -= 1 result[edi] = dl edi +=1 #print "\t1esi: %x edi : %x cl : %s dl : %s result :%s" % (esi,edi,cl, dl, ''.join(result)) #time.sleep(1) return ''.join(result) def engine(salt = 0x35190501, maxiter = 1000): domains = [] #salt = 0x35190501 #maxiter = 1000 for i in range(maxiter) : hashit, edx = seeder(i, salt) print "hashit : "+hashit hashstash = [int(hashit[:8],16), int(hashit[8:16],16),int(hashit[16:24],16),int(hashit[24:],16)] domain = '' if True : #while len(domain) < 0x10 : index = 0 for hashlet in hashstash: print "Hashlet : %x"% hashlet domain += generateDomain(socket.htonl(hashlet) & 0xFFFFFFFF) print "\t[%d] Domain : %s" % (index, domain) index += 1 print "[%d] Domain : %s\n" % (i, domain) ######################### if (edx & 3 == 0) : domain += ".\x63\x6F\x6D" elif (edx % 3 != 0 ) : if (edx & 1 != 0) : domain += ".\x6E\x65\x74" else : domain += ".\x62\x69\x7A" else : domain += ".\x6F\x72\x67" ######################### domains.append(domain) return domains index = 0 dt = str(datetime.datetime.now()).split(' ')[0] domains = engine() fp = open("gzdga_domains_"+dt+".txt","w") for domain in domains: a = dt+" | %d | %s\n" % (index, domain) fp.write(a) print a index += 1 fp.close()
https://www.virustotal.com/en/file/3...d0e6/analysis/
---------------XXX-------------
Happy Reversing : Stay turned on our social media page for more update:
https://www.facebook.com/Garage4Hackers
https://twitter.com/garage4hackers
Regards,
Garage4Hackers![]()