Mastering Malware Analysis Chapter 4

识别壳

  1. 使用PEID等工具
  2. 看节的名字,比如.UPX0等
  3. 看入口点是不是不在第一个节,壳的一般入口点都在最后几个节中,第一个节的属性通常是READ| WRITE
  4. 看导入表的大小,在加了壳的程序中,导入表一般是非常的小的。

自动的脱壳

  1. 官方脱壳工具,比如UPX的,但是一般攻击者会修改几个模数使官方的工具无法脱壳,比如,修改了节表名,.UPX0改为其他的名字
  2. OllyScript,可以对OllyScript写脚本啥的
  3. 通用的脱壳机:比如QuickUnpack(感觉要淘汰了,这个玩意
  4. 仿真(比如unipacker,一个基于Unicorn的引擎)
  5. 内存dumps

手动脱壳

手动脱壳和前面提到的自动脱壳的技术主要的区别是 何时进行内存dump以及dump之后需要干什么。如果我们仅仅执行原始的样本,dump内存,然后希望unpacked的模块也可以获得的话,我们将要面对多个问题。

  1. 运行起来后IAT表都填了真实的数据,需要恢复IAT表,甚至可能处理重定位表等问题。
  2. 哈希值与原始样本不同
  3. 原始的loader可能解包样本到allocated的内存中,然后free了,导致dump的不全
  4. 很容易漏掉一些模块;例如,原来的加载程序可能只解压缩32位或64位平台的示例

因此,最好的方法就是在original 样本的OEP那里停止,因为他已经Unpack完毕,并且没有继续往下进行,在这种情况下dump修复最好。

在执行时的内存断点

这项技术仅仅适用于 unpack后的程序的imagebase和packed后的程序的Imagebase相同的情况下。正如我们知道的,packed的样本肯定包含original样本的数据,所以unpack后,控制权就是到OEP,然后程序正常执行。我们假设OEP在第一个SECTION,所以,我们设置一个断点在那里。

设置断点

将第一个SECTION的属性设置为READ/WRITE, 这样就不可执行了。但是默认情况下,在多个WIndows版本中,它对于非关键进程仍然是可执行的,即使内存权限不包含EXECUTE权限,因此需要开启DEP

开启DEP

高级系统设置–>性能–>设置–>数据执行保护

现在,这个类型的断点应该就可以实施了,而且恶意软件将会被阻止在这个节执行,特别是在OEP的位置。

阻止任何更改内存权限的进一步尝试

不幸的是,仅仅强制执行DEP是不够的,这个unpacking stub能够容易的绕过这个断点,通过使用VirtualProtect​这个API来改内存权限。可以在这个API下断点进行监控,如果修改的话,直接将参数设置为READONLY或者READ| WRITE即可。

执行然后到达OEP

这里理论上会触发Access violation 异常,然后停在那,但是自己测试的时候并没有,而是直接终止了^(暂时不清楚是啥原因)^

调用堆栈回溯

就是在程序执行的过程中下断点,然后这个时候程序其实已经执行了一小段了,在这个地方栈回溯一点点的找,就能找到OEP

在哪个地方下断点??? 可以先行为监控下这个程序,比如APIMONITOR,然后在一些API那里下断点(比如 GetModuleFileNameA,
GetCommandLineA, CreateFileA, VirtualAlloc, HeapAlloc, and memset),

(感觉此方法不大实用

监控为unpacked 代码分配的空间

这个方法还是很有用的,

监控一些API,比如

  • VirtualAlloc/VirtualAllocEx/VirtualAllocExNuma
  • LocalAlloc/GlobalAlloc/HeapAlloc
  • RtlAllocateHeap

如果分配空间很大的话,一般就是解密了,可以在分配空间那个地方下断点

当然,像UPX这种并没有调用这些API,

那是在加载的时候,操作系统会帮申请, 直接在Write的地方下断点即可

In-place unpacking(就地解包???)

虽然不常见,但可以在示例最初所在的同一节(此节应具有写入|执行权限)或在原始文件的另一节中解密示例。

这里的意思应该是找到大的加密块,然后找哪个地方对这个加密块进行解密,通过这里,来最终定位到解密完成的地方,然后找到OEP

寻找跳转到OEP的指令

一般最后跳转到OEP都是Jmp过去的,有2种

  1. 第一种是编译的时候不知道OEP的位置,所以一般是jmp eax,或jmp 某个寄存器或者jmp某个偏移

  2. 第二种是编译的时候知道了OEP的位置,但是由于是直接静态看,还没有开始unpack,所以跳转过去的指令肯定是还没有解密的,即很有可能是密文或者直接是全是0,或者未分配

(原来脱壳还能这样,感觉很有用

基于栈恢复

ESP大法脱壳应该就是属于这种

DUMP unpacked的样本并且修复IAT

DUMP进程

可以使用OD的插件,OllyDump

或者PETools(32)或Lord PE (32)或者VSD(32/64)

修复IAT

为什么需要修复导入表???

因为原来的导入表被填充了真实的地址,而这个地址再次加载的话不一定是正确的,所以需要修复导入表。

IAT的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef struct _IMAGE_THUNK_DATA32 {
union {
DWORD ForwarderString;
DWORD Function;
DWORD Ordinal; //序号
DWORD AddressOfData; //指向 _IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA32;


typedef struct _IMAGE_IMPORT_BY_NAME {
WORD Hint; //可能为空,编译器决定,如果不为空,是函数在导出表中的索引(不是序号)
CHAR Name[1]; //函数名称,以0结尾
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

为了恢复导入表,需要搜寻API地址s,然后用对应的名字或者序号去替换它

利用ImportREC即可

对于64位系统,the Scylla or CHimpREC tools can be used instead.

高级对称和非对称加密算法

像RC4这种简单的算法,Malware会自己实现它的算法,然而像DES, AES或者RSA这种算法的实现,通常恶意软件作者不会自己去写算法,而是去调用API实现。我们需要做的是识别算法、加密/解密密钥和数据

从Windows加密APIs提取信息

一些常用的API用于提供对加密算法的访问,包含DES, AES, RSA甚至是RC4加密,这些APIs是CryptAcquireContext, CryptCreateHash,CryptHashData, CryptEncrypt, CryptDecrypt, CryptImportKey, CryptGenKey,CryptDestroyKey, CryptDestroyHash,, and CryptReleaseContext (来自Advapi32.dll)

恶意软件如何使用这些API

1. 初始化并连接到加密服务提供者

英文叫cryptographic service provider,即CSP,他是一个库,用来实施在Windows上的加密相关的API,对于恶意软件初始化和使用CSP中的一个的话,它执行CryptAcquireContext​API,

正如下面这样

1
CryptAcquireContext(&hProv,NULL,MS_STRONG_PROV,PROV_RSA_FULL,0);

能在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider​看到所有支持的CSP

2. 准备key

  1. 把自己准备的plain text key进行hash

    1
    2
    CryptCreateHash(hProv,CALG_MD5,0,0,&hHash);
    CryptHashData(hHash,secretkey,secretkeylen,0);
  2. 使用CryptDeriveKey创建session key, 从第二个参数很容易识别这个加密算法

    1
    2
    3
    4
    5
    CALG_DES = 0x00006601 // DES encryption algorithm.
    CALG_3DES = 0x00006603 // Triple DES encryption algorithm.
    CALG_AES = 0x00006611 // Advanced Encryption Standard (AES).
    CALG_RC4 = 0x00006801 // RC4 stream encryption algorithm.
    CALG_RSA_KEYX = 0x0000a400 // RSA public key exchange algorithm
  3. 一些恶意软件作者使用KEYBLOB结构,然后利用CryptImportKey​导入KEY

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
typedef struct KEYBLOB {  
BYTE bType; // 类型 PLAINTEXTKEYBLOB (0x8) PRIVATEKEYBLOB (0x7) PUBLICKEYBLOB (0x6)
BYTE bVersion;
WORD reserved;
ALG_ID aiKeyAlg; //aiKeyAlg就是具体的加密算法类型,是上面的2中的类型,比如0X6601代表CALG_DES
DWORD KEYLEN; //key的长度
BYTE[] KEY; //真正的KEY
}

// ******************比如下面************************
BYTE DesKeyBlob[] = { 0x08, //代表PLAINTEXTKEYBLOB
0x02, //版本
0x00,0x00, //保留
0x01,0x66,0x00,0x00, //CALG_DES
// BLOB header 是上面8个字节
0x08,0x00,0x00,0x00, // key length, in bytes
0xf1,0x0e,0x25,0x7c,0x6b,0xce,0x0d,0x34 // DES key with parity
};


3. 加密或解密数据

1
2
CryptEncrypt(hKey,NULL,1,0,cyphertext,ctlen,sz);
CryptDecrypt(hKey,NULL,1,0,plaintext,&ctlen);

4. 释放内存

这是最后一步,利用CryptDestroyKey​ 释放内存和所有的句柄

Cryptography API: Next Generation (CNG)

这是被微软实施的新一代的APIs,虽然在恶意软件中还没有广泛使用,但它们更容易理解并从中提取信息。

具体使用↓

1
2
3
4
BCryptOpenAlgorithmProvider(&hAesAlg, BCRYPT_AES_ALGORITHM, NULL, 0) //1. 初始化加密算法提供者
BCryptGenerateSymmetricKey(hAesAlg, &hKey, pbKeyObject,cbKeyObject, (PBYTE)SecretKey, sizeof(SecretKey), 0) //2. 准备key
BCryptEncrypt(hKey, pbPlainText, cbPlainText, NULL, pbIV, cbBlockLen, NULL, 0, &cbCipherText, BCRYPT_BLOCK_PADDING) //3. 加密数据
BCryptCloseAlgorithmProvider, BCryptDestroyKey, HeapFree //4. 清理工作

加密技术在现在恶意软件中的应用–Vawtrak银行木马

在这里,我们将研究恶意软件代码中用于混淆和隐藏恶意密钥特征的这些加密算法的其他实现。这些关键特征可用于使用静态签名甚至网络签名来识别恶意软件家族。

在本节中,我们将了解一种名为Vawtrak的已知银行木马。我们将看到这个恶意软件家族如何加密它的字符串和API名称,并混淆它的网络通信。

字符串和API名字加密

。。。这里用了个很简单的加密算法,就不看了。打CTF遇到过类似的,就是把字符串和API全都加密存起来,用的时候再解密,然后通过LoadLibrary加载需要的库,通过GetProcAddress来获取所用的函数的地址。

网络流量加密

没有什么好的方法去识别加密算法,只能是对一些网络发包或者收包的API进行下断点(HttpAddRequestHeadersA),然后追踪,打CTF的时候分析过这种。比如下面这个题,

https://www.52pojie.cn/thread-1551240-1-1.html

使用IDA来解密和脱壳

IDA tips和tricks

  1. 使用FindCrypt​, IDAscope​, or IDA Signsrch​可以识别加密算法,或者使用capa​这个工具,capa是纯静态的

  2. 了解到D810​这个插件,可以去混淆

  3. 恶意软件经常使用一些开源库,比如OpenSSL,这是静态连接到程序里的,去分析这些函数很浪费时间,所以可以生成一些sig文件,这样IDA就会自动的识别出函数名字来。

    诸如FLIRTDBsig-database之类的开源项目为许多操作系统的OpenSSL库提供了FLIRT签名,FLIRT的全程是Fast Library Identification and Recognition Technology

    • 先生成一个.lib文件

    • 从官网下载Flair的程序,里面包含一系列的工具,比如生成PAT的,以及sigmake工具等

    • 使用pcf生成PAT文件,使用sigmake将PAT变为sig文件,把它放到ida的sig目录下

    • Go to View | Open subviews | Signatures (the Shift + F5 hotkey). 就可以用了

      创建自定义FLIRT签名的另一个流行选项是idb2pat工具。

  4. 默认情况下,IDA在打开文件时运行自动分析,这意味着以后解密的任何代码都不会被分析(比如SMC这种)。可以点击IDA的左下角进行重新分析。

  5. funcap​这个插件可以记录运行时各个函数的参数,注释的形式添加进去