Sha1: 7c0118a02867c5481bbe8b9b228fc9d0f47167b8
Sha256: c89c825c3554d8e1b4bee8096494d8bf08deab3121d104858b5e86ec318ea286
“Trickbot” is not a new malware
but one of the popular banking Trojan that spread through e-mail nowadays. This
malware uses a crypter/packer to hide its code from detection, but upon
manually unpacking it you will see right away a very notable series of jumbled
string (Modified base64) that really give us hint that they are encrypted.
Figure 1. The encoded strings of an unpacked version of Trickbot |
But
even the encrypted strings are expose on the unpack version of the malware you
cannot directly cross reference the functions that uses the encrypted string, because
Trickbot malware create an index table that contains the VA of each encrypted
string and reference it dynamically using the pointer (DWORD) of each VA
address. Sort of anti-static analysis technique.
Figure 2. There is no xref for the encrypted string |
The Xref
functions that use the SubDecFunc with some short description:
SubDecFunc – The actual
decryption routine with 2 arguments, the pointer index of encrypted string to
its table that contain the VA’s of the encrypted string and the allocated space
where the decrypted value will be place.
Sub_SetupDecryption – Function That will
call the SubDecFunc. That also has 2 the same arguments.
Sub_DecSetup1, Sub_DecSetup2, Sub_DecSetup3 = Function That can call Sub_SetupDecryption with same number and
arguments values.
And from those 3 Sub_DecSetup*
function there are couple of xref functions that uses it, where the inputting
of the index and the output buffer as arguments of decryption routine take
place. In this type of scenario we need more time to analyze each xref
functions to decrypt all the strings, so it is much better to use scripting
language like python to automate this.
Figure 3. Xref Function using the decryption routine |
Figure 3.1. decoding flow of this malware |
Decryption routine:
The structure of the encrypted and the decryption key in the file.
Figure 4. Encrypted File structure with the decryption routine |
Figure 6. Decrpytion Routine |
A simple explanation of its decryption routine.
1.
First it will get the
length of the encrypted string.
2.
The decryption
routine was designed to process 4 encrypted bytes at a time that’s why it needs
to group the string into DWORD.
3.
after having a dword
value, it will locate the position of each byte character (index of the byte) on
that DWORD from the decryption key string and that index position will be the
initial key to decrypt the actual value using some shift logical function in
decryption_1.
4.
If an instance that
the string is not divisible by 4. It will check how many bytes are need to have
a DWORD value during grouping. By using Memset API it will fill the needed
bytes with \x00 or null byte to form DWORD value, then find the index of each
byte and used the decryption_2 to decrypt it.
limit =
enc_str_len
dec_str = ""
while limit:
if limit >= 4:
dec_bytes = initialized_var(size)
for i in range (0, 4):
index_ptr = locate_index(enc_str[index + i])
dec_bytes[i] = index_ptr
limit -= 4
index = index + i + 1
dec_str = decryption_routine_1(dec_bytes, dec_str)
else:
dec_bytes = initialized_var(size)
for i in range(0, limit):
index_ptr = locate_index(enc_str[index + i])
dec_bytes[i] = index_ptr
limit -= limit
index = index + i + 1
dec_str = decryption_routine_2(dec_bytes, dec_str)
print dec_str
return
dec_str = ""
while limit:
if limit >= 4:
dec_bytes = initialized_var(size)
for i in range (0, 4):
index_ptr = locate_index(enc_str[index + i])
dec_bytes[i] = index_ptr
limit -= 4
index = index + i + 1
dec_str = decryption_routine_1(dec_bytes, dec_str)
else:
dec_bytes = initialized_var(size)
for i in range(0, limit):
index_ptr = locate_index(enc_str[index + i])
dec_bytes[i] = index_ptr
limit -= limit
index = index + i + 1
dec_str = decryption_routine_2(dec_bytes, dec_str)
print dec_str
return
def decryption_routine_1(dec_bytes, dec_str):
al = dec_bytes[1]
cl = dec_bytes[0]
dl = dec_bytes[1]
al = sar(al, 4)
cl = (cl << 2) & 0xFF
al += cl
dec_str += chr(al)
al = dec_bytes[2]
cl = al
cl = sar(cl, 2)
al = (al << 6) & 0xFF
al += dec_bytes[3]
cl &= 0x0f
dl = (dl << 4) & 0xFF
cl ^= dl
dec_str += chr(cl)
dec_str += chr(al)
return dec_str
al = dec_bytes[1]
cl = dec_bytes[0]
dl = dec_bytes[1]
al = sar(al, 4)
cl = (cl << 2) & 0xFF
al += cl
dec_str += chr(al)
al = dec_bytes[2]
cl = al
cl = sar(cl, 2)
al = (al << 6) & 0xFF
al += dec_bytes[3]
cl &= 0x0f
dl = (dl << 4) & 0xFF
cl ^= dl
dec_str += chr(cl)
dec_str += chr(al)
return dec_str
def decryption_routine_2(dec_bytes, dec_str):
al = dec_bytes[1]
cl = dec_bytes[0]
dl = dec_bytes[1]
al = sar(al, 4)
cl = (cl << 2) & 0xFF
al &= 3
al = al + cl
dec_str += chr(al)
al = dec_bytes[2]
cl = al
cl = sar(cl, 2)
cl &= 0x0f
dl = (dl << 4) & 0xff
al = (al << 6) & 0xff
al += dec_bytes[3]
cl ^= dl
dec_str += chr(cl)
dec_str += chr(al)
return dec_str
al = dec_bytes[1]
cl = dec_bytes[0]
dl = dec_bytes[1]
al = sar(al, 4)
cl = (cl << 2) & 0xFF
al &= 3
al = al + cl
dec_str += chr(al)
al = dec_bytes[2]
cl = al
cl = sar(cl, 2)
cl &= 0x0f
dl = (dl << 4) & 0xff
al = (al << 6) & 0xff
al += dec_bytes[3]
cl ^= dl
dec_str += chr(cl)
dec_str += chr(al)
return dec_str
Decrypted string:
Below you can see some notable
decrypted string that may give us some help in analyzing the said malware.
Some of the API/modules
it will parse and use during dynamic execution.
UnloadUserProfile
LoadUserProfileW
DestroyEnvironmentBlock
CreateEnvironmentBlock
USERENV.dll
GetAdaptersInfo
IPHLPAPI.dll
NtQueryInformationProcess
ntdll.dll
PathFindExtensionW
PathRemoveFileSpecW
PathRemoveBackslashW
StrStrIW
PathRenameExtensionW
PathAddBackslashW
PathFindFileNameW
SHLWAPI.dll
CryptBinaryToStringW
CryptStringToBinaryW
CRYPT32.dll
CoUninitialize
CoCreateInstance
ole32.dll
SetSecurityDescriptorDacl
InitializeSecurityDescriptor
CopySid
GetLengthSid
SetEntriesInAclW
GetSecurityInfo
SetSecurityInfo
SetNamedSecurityInfoW
RegSetValueExW
RegOpenKeyExW
RegCloseKey
RegCreateKeyExW
RevertToSelf
AdjustTokenPrivileges
LookupPrivilegeValueW
CryptGetHashParam
CryptAcquireContextW
CryptSetKeyParam
CryptReleaseContext
ConvertStringSecurityDescriptorToSecurityDescriptorW
CryptImportKey
CryptCreateHash
CryptDecrypt
CryptDestroyHash
CryptHashData
CryptDestroyKey
AllocateAndInitializeSid
FreeSid
OpenProcessToken
EqualSid
CreateProcessAsUserW
DuplicateTokenEx
LookupAccountSidW
GetTokenInformation
GetUserNameW
ADVAPI32.dll
CreateToolhelp32Snapshot
Process32NextW
Process32FirstW
MultiByteToWideChar
WideCharToMultiByte
GetModuleHandleA
QueryPerformanceCounter
GetCurrentThreadId
SetUnhandledExceptionFilter
UnhandledExceptionFilter
lstrlenA
GetCurrentProcessId
GetSystemTimeAsFileTime
GetCurrentProcess
GetVersionExW
GetVersion
SetFilePointer
WriteFile
ReadFile
CreateFileW
lstrcmpiW
GetTempFileNameW
CreateProcessW
MoveFileExW
GetTickCount
InitializeCriticalSectionAndSpinCount
Sleep
GetFileAttributesW
GetModuleFileNameW
GetStartupInfoW
GetTempPathW
MoveFileW
SetCurrentDirectoryW
DeleteFileW
lstrcpyW
LocalFree
CreateMutexW
ResumeThread
WriteProcessMemory
DuplicateHandle
CreateEventW
GetExitCodeThread
VirtualAllocEx
VirtualProtectEx
TerminateProcess
ReadProcessMemory
VirtualFreeEx
OpenProcess
CreateRemoteThread
SetEvent
CreateDirectoryW
SetFileAttributesW
lstrcmpA
LoadLibraryA
GetFileTime
FindNextFileW
GetSystemInfo
LockResource
FindClose
GetLastError
lstrcpynW
SetFileTime
GetModuleHandleW
LoadResource
FreeLibrary
FindResourceW
FindFirstFileW
GetFullPathNameW
lstrlenW
lstrcmpW
GetComputerNameW
CreateThread
WTSQueryUserToken
WTSGetActiveConsoleSessionId
WTSFreeMemory
WTSEnumerateSessionsA
wtsapi32
GetProcAddress
LoadLibraryW
ExitProcess
ResetEvent
CloseHandle
WaitForSingleObject
SignalObjectAndWait
InternetCanonicalizeUrlW
Wininet
BCryptDestroyKey
BCryptCloseAlgorithmProvider
BCryptVerifySignature
BCryptGetProperty
BCryptImportKeyPair
BCryptOpenAlgorithmProvider
NCryptFreeObject
NCryptDeleteKey
NCryptImportKey
NCryptOpenStorageProvider
Bcrypt.dll
Ncrypt.dll
HeapReAlloc
HeapFree
GetProcessHeap
HeapAlloc
kernel32.dll
Some Website
that checks the ip address of the local machine:
ip.anysrc.net
wtfismyip.com
myexternalip.com
icanhazip.com
api.ipify.org
ipinfo.io
ipecho.net
checkip.amazonaws.com
other url
domain:
spam.dnsbl.sorbs.net
dnsbl-1.uceprotect.net
b.barracudacentral.org
cbl.abuseat.org
zen.spamhaus.org
Registry
entries it used to exclude its drop file from WinDefender anti-virus.
MACHINE\SOFTWARE\Microsoft\Microsoft
Antimalware\Exclusions\Paths
MACHINE\SOFTWARE\Policies\Microsoft\Windows
Defender\Exclusions\Paths
MACHINE\SOFTWARE\Microsoft\Windows
Defender\Exclusions\Paths
Possible
targeted machine:
x86
x64
Unknown
Windows 2000
Windows XP
Windows Server 2003
Windows Vista
Windows Server 2008
Windows 7
Windows Server 2008 R2
Windows 8
Windows Server 2012
Windows 8.1
Windows Server 2012 R2
Windows 10
Windows 10 Server
Browser
agent that it may use with its GET and POST traffic:
0.0.0.0
POST
GET
Mozilla/5.0 (Windows NT 10.0;
WOW64; rv:59.0) Gecko/20100101 Firefox/59.0
An xml
string that may give us a hint for other stuff it will try to do.
</Command>
</Exec>
</Actions>
</Task>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
<AllowHardTerminate>false</AllowHardTerminate>
<StartWhenAvailable>true</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>true</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions
Context="Author">
<Exec>
<Command>
</StartBoundary>
<Enabled>true</Enabled>
<ScheduleByDay>
<DaysInterval>1</DaysInterval>
</ScheduleByDay>
</CalendarTrigger>
</Triggers>
<Principals>
<Principal
id="Author">
<CalendarTrigger>
<Repetition>
<Interval>PT3M</Interval>
<Duration>P1D</Duration>
<StopAtDurationEnd>false</StopAtDurationEnd>
</Repetition>
<StartBoundary>
<?xml version="1.0"
encoding="UTF-16"?>
<Task version="1.2"
xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Version>1.0.1</Version>
<Description>System service
monitor.</Description>
<URI>\Task</URI>
</RegistrationInfo>
<Triggers>
Conclusion:
scripting language is really helpful to automate the analysis and make the Reverse engineering more easier. Analyzing some interesting stuff keeps me improve in Reverse Engineering :) hope you enjoy!!!