AlphaBlend Campaign Part 3

in reverseengineering •  25 days ago

This continues the reversing journey of the malicious DLL, msimg32.dll, and the AlphaBlend campaign. Now that I covered how to circumvent the SEH-based anti-debugging capability, we will look more carefully at the behavior before the exception is raised. There are various functions that prepare resources for the malware as well as an interesting set of functions to resolve the dll names and API that the malware uses. I hope everyone is enjoying this series. Please reach out to me with any questions.

This first function shown in red below can perform a few checks for the malware’s environment.

outer_graph.png

In the next graph screenshot, one can see that the function checks for time, IDs, and tick count. This is not executed the first time the function is called, but it has this capability.

check_env.png

Once this environment check is run, the SEH is then set. With that set, the malware performs a few steps of setup. This is a basic outline of these steps, including ones previously mentioned:

  1. Check environment
  2. Set SEH
  3. Set thread variable
    1. Set Actx thread variable via InterlockedExchange
    2. Malloc something
    3. Call InterlockedExchange
  4. Dosomething
    1. CreateCompatibleDC
    2. Dosomething
      1. Set background mix for device context: transparent
      2. Resolve DLLs
        1. ntdll.dll
        2. kernel32.dll
      3. Resolve API

The Actx string that I observed in previous reports is used as a thread variable. It is set as such using InterlockedExchange. Between the two steps of setting the thread variable, memory is allocated. Unfortunately, I don’t have good names yet for certain functions, so I’m using Dosomething as a placeholder. The step CreateCompatibleDC creates memory device context compatible with the current screen. Then it sets the background mix for the new device context to transparent.

The next set of steps that it takes are quite interesting. I’m a subscriber to the excellent OALabs YouTube channel, and if you follow that link, you will see a video about how malware resolves its API from stack strings. This keeps the strings from appearing during static analysis. The AlphaBlend sample does not take exactly this way to resolve the API, but it is very similar in aim. The next image shows the malware’s process. This also shows how the malware uses the string K/\f that I covered in a previous blog post. This string is used as a counter compared to L’S’ until it matches and the function returns.

resolve_api.png

The number of function names that the malware resolves is quite high. Therefore, I used the trace functionality in x64dbg to log the contents of esi across the resolve_api function. All that’s needed is a path to log to and a formatting string for the log entries. I used something simple: esi: {esi} {s:esi}\n. This provides the name of the register, the address, and the string. This part of the process starts with setting a breakpoint on the resolve_api function call.

set_breakpoint.png

Next, step into the function and start the trace log using the formatting string.

set_trace.png

Now rather than stepping through the function and wasting tons of time, I can run until return and collect all those juicy API strings. This is a great time to highlight an invaluable tool: Jupyter. This is a notebook programming tool that is primarily for Python, but supports many third party kernels for various other languages. Notebook programming is somewhere between the two traditional ways that Python code is run: read–eval–print loop (REPL) and monolithic script. It allows you to run code blocks, or cells, in any order you need. It comes in two flavors: notebook and lab. I use lab even though it has not been released stable. It’s plenty stable for my needs.

log_processing.png

With this technique, the list of function names in the API that the malware wanted to hide are easily recovered. In the appendix below, both the Jupyter notebook for log processing as well as the list of function names is provided (add your own path!).

In another pathway of analysis, I have been examining the results from retrohunts on various code blocks in the DLL. I’ve discovered that the section with the AlphaBlend exports is located in a section of code that is variable across samples. The following shows the difference between the sample in the AlphaBlend campaign and other samples that are clearly in the same malware family, but in other campaigns.

campaigns_side_by_side.png

The part of the code that does not vary appears to be a stub that the adversary uses with different code based on campaign.

This concludes this episode of the AlphaBlend reversing saga. I hope everyone is finding this all valuable. Stay tuned for the next post!

Appendix

['AcquireSRWLockExclusive',
 'AcquireSRWLockShared',
 'ActivateActCtx',
 'AddAtomA',
 'AddAtomW',
 'AddConsoleAliasA',
 'AddConsoleAliasW',
 'AddIntegrityLabelToBoundaryDescriptor',
 'AddLocalAlternateComputerNameA',
 'AddLocalAlternateComputerNameW',
 'AddRefActCtx',
 'AddSIDToBoundaryDescriptor',
 'AddSecureMemoryCacheCallback',
 'AddVectoredContinueHandler',
 'AddVectoredExceptionHandler',
 'AdjustCalendarDate',
 'AllocConsole',
 'AllocateUserPhysicalPages',
 'AllocateUserPhysicalPagesNuma',
 'ApplicationRecoveryFinished',
 'ApplicationRecoveryInProgress',
 'AreFileApisANSI',
 'AssignProcessToJobObject',
 'AttachConsole',
 'BackupRead',
 'BackupSeek',
 'BackupWrite',
 'BaseCheckAppcompatCache',
 'BaseCheckAppcompatCacheEx',
 'BaseCheckRunApp',
 'BaseCleanupAppcompatCacheSupport',
 'BaseDllReadWriteIniFile',
 'BaseDumpAppcompatCache',
 'BaseFlushAppcompatCache',
 'BaseFormatObjectAttributes',
 'BaseFormatTimeOut',
 'BaseGenerateAppCompatData',
 'BaseGetNamedObjectDirectory',
 'BaseInitAppcompatCacheSupport',
 'BaseIsAppcompatInfrastructureDisabled',
 'BaseQueryModuleData',
 'BaseSetLastNTError',
 'BaseThreadInitThunk',
 'BaseUpdateAppcompatCache',
 'BaseVerifyUnicodeString',
 'Basep8BitStringToDynamicUnicodeString',
 'BasepAllocateActivationContextActivationBlock',
 'BasepAnsiStringToDynamicUnicodeString',
 'BasepCheckAppCompat',
 'BasepCheckBadapp',
 'BasepCheckWinSaferRestrictions',
 'BasepFreeActivationContextActivationBlock',
 'BasepFreeAppCompatData',
 'BasepMapModuleHandle',
 'Beep',
 'BeginUpdateResourceA',
 'BeginUpdateResourceW',
 'BindIoCompletionCallback',
 'BuildCommDCBA',
 'BuildCommDCBAndTimeoutsA',
 'BuildCommDCBAndTimeoutsW',
 'BuildCommDCBW',
 'CallNamedPipeA',
 'CallNamedPipeW',
 'CallbackMayRunLong',
 'CancelDeviceWakeupRequest',
 'CancelIo',
 'CancelIoEx',
 'CancelSynchronousIo',
 'CancelThreadpoolIo',
 'CancelTimerQueueTimer',
 'CancelWaitableTimer',
 'ChangeTimerQueueTimer',
 'CheckElevation',
 'CheckElevationEnabled',
 'CheckForReadOnlyResource',
 'CheckNameLegalDOS8Dot3A',
 'CheckNameLegalDOS8Dot3W',
 'CheckRemoteDebuggerPresent',
 'ClearCommBreak',
 'ClearCommError',
 'CloseConsoleHandle',
 'CloseHandle',
 'ClosePrivateNamespace',
 'CloseProfileUserMapping',
 'CloseThreadpool',
 'CloseThreadpoolCleanupGroup',
 'CloseThreadpoolCleanupGroupMembers',
 'CloseThreadpoolIo',
 'CloseThreadpoolTimer',
 'CloseThreadpoolWait',
 'CloseThreadpoolWork',
 'CmdBatNotification',
 'CommConfigDialogA',
 'CommConfigDialogW',
 'CompareCalendarDates',
 'CompareFileTime',
 'CompareStringA',
 'CompareStringEx',
 'CompareStringOrdinal',
 'CompareStringW',
 'ConnectNamedPipe',
 'ConsoleMenuControl',
 'ContinueDebugEvent',
 'ConvertCalDateTimeToSystemTime',
 'ConvertDefaultLocale',
 'ConvertFiberToThread',
 'ConvertNLSDayOfWeekToWin32DayOfWeek',
 'ConvertSystemTimeToCalDateTime',
 'ConvertThreadToFiber',
 'ConvertThreadToFiberEx',
 'CopyContext',
 'CopyFileA',
 'CopyFileExA',
 'CopyFileExW',
 'CopyFileTransactedA',
 'CopyFileTransactedW',
 'CopyFileW',
 'CopyLZFile',
 'CreateActCtxA',
 'CreateActCtxW',
 'CreateBoundaryDescriptorA',
 'CreateBoundaryDescriptorW',
 'CreateConsoleScreenBuffer',
 'CreateDirectoryA',
 'CreateDirectoryExA',
 'CreateDirectoryExW',
 'CreateDirectoryTransactedA',
 'CreateDirectoryTransactedW',
 'CreateDirectoryW',
 'CreateEventA',
 'CreateEventExA',
 'CreateEventExW',
 'CreateEventW',
 'CreateFiber',
 'CreateFiberEx',
 'CreateFileA',
 'CreateFileMappingA',
 'CreateFileMappingNumaA',
 'CreateFileMappingNumaW',
 'CreateFileMappingW',
 'CreateFileTransactedA',
 'CreateFileTransactedW',
 'CreateFileW',
 'CreateHardLinkA',
 'CreateHardLinkTransactedA',
 'CreateHardLinkTransactedW',
 'CreateHardLinkW',
 'CreateIoCompletionPort',
 'CreateJobObjectA',
 'CreateJobObjectW',
 'CreateJobSet',
 'CreateMailslotA',
 'CreateMailslotW',
 'CreateMemoryResourceNotification',
 'CreateMutexA',
 'CreateMutexExA',
 'CreateMutexExW',
 'CreateMutexW',
 'CreateNamedPipeA',
 'CreateNamedPipeW',
 'CreatePipe',
 'CreatePrivateNamespaceA',
 'CreatePrivateNamespaceW',
 'CreateProcessA',
 'CreateProcessAsUserW',
 'CreateProcessInternalA',
 'CreateProcessInternalW',
 'CreateProcessW',
 'CreateRemoteThread',
 'CreateRemoteThreadEx',
 'CreateSemaphoreA',
 'CreateSemaphoreExA',
 'CreateSemaphoreExW',
 'CreateSemaphoreW',
 'CreateSocketHandle',
 'CreateSymbolicLinkA',
 'CreateSymbolicLinkTransactedA',
 'CreateSymbolicLinkTransactedW',
 'CreateSymbolicLinkW',
 'CreateTapePartition',
 'CreateThread',
 'CreateThreadpool',
 'CreateThreadpoolCleanupGroup',
 'CreateThreadpoolIo',
 'CreateThreadpoolTimer',
 'CreateThreadpoolWait',
 'CreateThreadpoolWork',
 'CreateTimerQueue',
 'CreateTimerQueueTimer',
 'CreateToolhelp32Snapshot',
 'CreateWaitableTimerA',
 'CreateWaitableTimerExA',
 'CreateWaitableTimerExW',
 'CreateWaitableTimerW',
 'CtrlRoutine',
 'DeactivateActCtx',
 'DebugActiveProcess',
 'DebugActiveProcessStop',
 'DebugBreak',
 'DebugBreakProcess',
 'DebugSetProcessKillOnExit',
 'DecodePointer',
 'DecodeSystemPointer',
 'DefineDosDeviceA',
 'DefineDosDeviceW',
 'DelayLoadFailureHook',
 'DeleteAtom',
 'DeleteBoundaryDescriptor',
 'DeleteCriticalSection',
 'DeleteFiber',
 'DeleteFileA',
 'DeleteFileTransactedA',
 'DeleteFileTransactedW',
 'DeleteFileW',
 'DeleteProcThreadAttributeList',
 'DeleteTimerQueue',
 'DeleteTimerQueueEx']

API

{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pathlib\n",
    "import re"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "log = pathlib.Path()\n",
    "log.exists()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open(log, 'r') as fh:\n",
    "    data = fh.read().splitlines()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "log_re = re.compile('(?P<register>[a-z]{3}): (?P<address>[A-Z0-9]+) (?:\\?\\?\\?|\"(?P<api>[A-Za-z0-9]+)\")')\n",
    "apis = list()\n",
    "first = True\n",
    "for entry in data:\n",
    "    match = re.match(log_re, entry)\n",
    "    if match:\n",
    "        if match.group('api'):\n",
    "            if first:\n",
    "                apis.append(match.group('api'))\n",
    "                first = False\n",
    "        else:\n",
    "            first = True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "apis"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}

Jupyter Notebook

For everyone who has read this far: Andy C!

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Don't judge each day by the harvest you reap but by the seeds that you plant.