---
# System prepended metadata

title: "HITCON Training 2019\n  揣摩軟體安全 - 學習系統攻防"

---

HITCON Training 2019
  揣摩軟體安全 - 學習系統攻防
===

* 課程附件:[Download link](https://drive.google.com/open?id=1FuZxvwXXkAQZsYV6JbNj2Ke-KcJLu3Lz)

* password:HitconTraining@@2019


# use debugger

## 靜態分析-IDApro 與他們的小夥伴
### 基本功能
- F5大法:一鍵還原source code
- space:shift view
- shift+f12:string search
- Hex <-> Ord 進位轉換 快捷鍵:H
- 重命名變數 快捷鍵:N 
- 找尋關鍵點引用 快捷鍵:X 
- 快速跳到指定位置: G 
- 回到上一步操作: ESC 
- 點選 API 按 Y 改函數 type "MACRO_PROCESS" 
    - 可以辨認出有 bitmask (openprocess函數)的參數 (不一定準確)
    - 在imports 
    ![](https://i.imgur.com/ZE4JyMD.png)
    - 按 Y 改函數 type "MACRO_PROCESS"
    ![](https://i.imgur.com/4pHdQgq.png)
    - 原本的變數就變成可讀性高的變數名稱


### ray式IDA
- IDA 佈景主題 plugin
    - https://github.com/zyantific/IDASkins/releases/ 
    - Unzip and copy “plugins”dir To C:\Program Files\IDA 7.0\
### YARA
- 很棒的內容搜索引擎
#### demo
- rule.txt:
![](https://i.imgur.com/KAF2X8a.png)
- command : yara + rule.txt + target_file
```
C:\Users\terry>C:\Users\terry\Downloads\HITCON2019\Tools\Yara\yara32.exe C:\Users\terry\Downloads\HITCON2019\Tools\Yara\rule.txt C:\Users\terry\Downloads\HITCON2019\Tools\Yara\rule.txt
test_yara_rule C:\Users\terry\Downloads\HITCON2019\Tools\Yara\rule.txt

# 看出現在哪
C:\Users\terry>C:\Users\terry\Downloads\HITCON2019\Tools\Yara\yara32.exe C:\Users\terry\Downloads\HITCON2019\Tools\Yara\rule.txt C:\Users\terry\Downloads\HITCON2019\Tools\Yara\rule.txt  -s
test_yara_rule C:\Users\terry\Downloads\HITCON2019\Tools\Yara\rule.txt
0xd7:$b: AABBCCDD
```
#### mkyara
- 一鍵產生yara rule
- install:![](https://i.imgur.com/UQVAxc6.jpg)
    1. 先灌pip
        ![](https://i.imgur.com/jxCpZIY.png)
    2. command line
    ```
    install pip
    cd c:\python27-x64>cd Scripts
        pip install mkyara
    ```
    3. 把
    ![](https://i.imgur.com/1inAqmC.png)
    4. 放到
    ![](https://i.imgur.com/pIoWYcW.png)
    5. 選取一段直接產生該段的rule
    ![](https://i.imgur.com/CkoKLyy.png)
- 自動辨認可能變動的值成為?
    ![](https://i.imgur.com/ZdMQKIs.png)

### FireEye stack string parse
- 自動化找尋隱藏字串
- install(cmd)
```
# copy the “~\HITCON2019\IDA Plugins\flare-ida-master\python,~\HITCON2019\IDA Plugins\flare-ida-masterplugins” dir to C: Program Files IDA 7.0

cd C:\python27-x64\Scripts>
pip install https://github.com/williballenthin/vivisect/zipball/master

```
- use
![](https://i.imgur.com/4zTa0mN.png)
![](https://i.imgur.com/BDTyiIe.png)

## 萬能F5(?
- demo_1(Anti IDA Trick1 - F5 Error)
    - IDA 非常重視 Stack 平衡 , 因此自行修改 Stack平衡就可能讓 IDA 解析錯誤. (__declspec function)
    - IDA 也會把 jmp 強制跳躍指令視為跳到另一個 function 執行 , 多加一個 label 達到欺騙的目的效果 
    -  F5 按下不能 QQ
```cpp=
//#include "pch.h"
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <stdio.h>

//example 1
//IDA 非常重視 Stack 平衡 , 因此自行修改 Stack平衡就可能讓 IDA 解析錯誤. (__declspec function)
void __declspec(naked) SecretFunc()
{
	printf("IDA~ are you see me!?");
	getchar();
	_asm
	{
		add esp, 0x4
		ret
	}
}

//example 2
//IDA 也會把 jmp 強制跳躍指令視為跳到另一個 function 執行 , 多加一個 label 達到欺騙的目的

void destroy_func()
{
	__asm
	{
		lea eax, lab1  //eax = lab1;
		jmp eax        //goto lab1;
		_emit 0x90     //0x90 == nop

	lab1:
	}
	printf("destroy_func\n");
}


int main(int argc, char *argv[])
{
	
	//example 1
	_asm
	{
		jmp dword ptr[SecretFunc]
	}

	//example 2
	//destroy_func();
	return 0;
}
```

- demo_2(Anti IDA Trick2)
    - IDA 對 SEH 解析有問題 , 不會顯示 except 後的結果 , 因此可自行觸發異常達成欺騙目的.
```cpp=
#include "pch.h"
#include <iostream>

int main()
{
	__try
	{
		printf("IDA what are you doing?\n");
		_asm
		{
			mov eax, 0 //eax = 0;
			mov eax, [eax] //eax = *0;  access zero address to trigger exception
		}
	}
	__except (1)
	{
		printf("Evil things you want. \n");
	}
	getchar();
	return 0;
}

```
![](https://i.imgur.com/Y124kGc.png)


## 動態分析(ollydgb/x64dbg)
![](https://i.imgur.com/GR7WFcS.png)
> EIP 現在正準備要執行的指令
- 基礎介面操作
    - 開啟目標的兩種方式 
        - 直接開啟(會以Debug Mode 開啟)
            - 影響某些記憶體行為,並更容易被偵測到有debugger存在
            - 直接拖進視窗裡面
        - 附加式開啟
            - 可繞過許多剛開始針對debugger 的檢測 
            - 先執行程式
            - 開dbg (檔案>:heart: 附加) 
            ![](https://i.imgur.com/04CKEV5.png)
- 分析目標確認(投影片等等再加)
> 先F9一次
- 快捷鍵們
    - F2 - 斷點 放置軟體斷點 , 像是陷阱的概念 , 程序執行遇到斷點後會暫停 , 將控制權交給 debugger (x64dbg) 
    - F7 - 單步步進 執行一行指令，**會進入function (call)** 中執行 
    - F8 - 單步步過 執行一行指令，**不會進入function (call)** 中執行 
    - F9 - 直接讓程式流程執行, 直到觸發斷點停下
    - F4 - 跳到滑鼠點選的記憶體位置 快速跳到指定的記憶體位置執行, 通常用在跳出多個for 迴圈，取代人力慢慢按F8
    - Ctrl + G : 跳到指定記憶體位置


# debugger 破解技巧& 軟體實戰
## 快快樂樂學組語
- 參數傳遞:由上到下，由左到右
![](https://i.imgur.com/PJWNrqF.jpg)
- mov aaa , bbb (等價於 C 語言中 aaa = bbb;) 
- mov aaa , [bbb]  (等價於 C 語言中 aaa = *bbb;) 
- push xxx (將 xxx 參數放入 stack 中) ，通常配合 call 指令使用 
- call   xxx ( 等價於 C 語言中 執行 xxx() 函數) • 
- jmp 0xaaaabbbb (無條件強制流程跳躍到記憶體0xaaaabbbb 執行) 
    - (等價於C語言中的goto 0xaaaabbbb;) 
    - 其他 J 開頭的指令都是根據某些條件，跳躍到其他記憶體執行 
- Nop • 
    - Nothing to do. 不做任何事 
- cmp aaa , bbb (比較 aaa , bbb 的數值) 
    - 通常配合 J 開頭的條件跳躍指令 
- ret   (返回上一個函數流程執行) (等價於 C 語言中的 return)


## Pdb File 的應用
- 主要用途：方便開發者 debug 使用 
- 進階用途：跟蹤 Project & 作者痕跡 (丟到hex editor)
- VS 開發設定：編譯去除選項(屬性 -> 連結器 -> 產生偵錯資訊 -> 否) 
    - 拿掉後逆向難度變高
## 指令暫存器的通用概念
- eip • 
    - 一定存放目前執行指令的記憶體位置 
- eax •
    -  函數返回值 (通常放這) 
    -  在一個 call 完成後退出時,要特別關心 eax (返回值) 
- ecx • 
    - 存放物件指標 (通常) 
    - for 的 i 計數器大小 (通常) , 通常會有一個累加的動作 , 類似 c 語言中的 i++
- esp •
    -  一定存放 Stack (堆疊)記憶體位置頂部 
- ebp 
    -  一定存放 Stack (堆疊)記憶體位置底部

### demo
- 基本驗證機制 Source Code
```cpp=
#include "pch.h"
//#include "stdafx.h"
#include "windows.h" //Windows API Library
#include <iostream>
int main()
{
    DWORD input_passwd = NULL;
    printf("Input password\n");
    std::cin >> input_passwd;

    if (input_passwd != 12345678)
    {
        MessageBoxA(0,"Regist Fail!!!" , "Notify" , MB_OK);
        return 0;
    }

```
#### 註冊/特殊字串搜索
- 任意地方右鍵>搜尋>目前模組>字串引用
![](https://i.imgur.com/TJtrbOZ.png)
![](https://i.imgur.com/Oc3dzTd.png)

#### 堆疊(Stack) 回逤法 
- 跳出錯誤提示時 , 快速按下暫停 , 並從堆疊中找線索 • <3> API 斷點法 • 常見的錯誤提示 API 斷點 • MessageBoxA / MessageBoxW • GetWindowTextA / GetWindowTextW 
- step
    - 等跳出messagebox的時候點擊彈出視窗按F12
    ![](https://i.imgur.com/HOOnTSd.png)
    - 然後進dbg按F9>再按暫停>進呼叫堆疊
    ![](https://i.imgur.com/WSWFCzl.png)
#### API 斷點法 
- step
    - 先執行程式，輸入隨便的數字，按下enter會跳到messagebox，設斷點
    ![](https://i.imgur.com/Rb2clcE.png)
    - 按F8繼續跑，跑到call messagebox會跳出fail
    ![](https://i.imgur.com/O9LfMw3.png)
    - 按下確定後按F8繼續跑會跳回判斷正確的函數，往上滑可以找到跳轉的地方(74 18 je -> jmp
    ![](https://i.imgur.com/7CMaIuC.png)
#### 工具法(API monitor)
- 進入工具攔截(左側選擇項目)
![](https://i.imgur.com/E0ZvotZ.png)
- 攔截到的進入點
![](https://i.imgur.com/cEHQqXF.png)
- 去gdb(ctrl+G)跳記憶體，找到程式進入點
![](https://i.imgur.com/OdOcOCb.png)

## 軟體驗證基本流程與破解練習
- 破解初探
    - 定位關鍵點 
    - Binary Patch
- 破解軟體授權(010editor)
    - 先把程式搞到一定要註冊完才能使用(方便查找)
    ![](https://i.imgur.com/IIJLEhf.png)
    - 隨便打個帳號密碼讓他噴訊息，然後搜尋字串"invalid name"
    ![](https://i.imgur.com/Xet52bO.png)
    - 找到程式判斷購買成功的地方，用二進位Nope填充不要跳到錯誤，通常找je等，會跳一大段的指令，中間通常有判斷或是讓驗證通過的地方，只要把開頭跳走的地方弄掉，就能卡進去
    ![](https://i.imgur.com/KQmDBEh.png)


## 軟體破解實戰 - 某知名的16進位編輯器的註冊破解
記在腦子裡  <- ??
剛剛那個完全破解
步驟太多了

# anti-debugger
## TEB / PEB 介紹

*    TEB(Thread Environment Block)
        *    存放許多和 Thread  有關的資訊 , ex:Image base / Path..
        *    透過組合語言指令取得: fs:[0]
*    PEB(Process Environment Block)
        *    存放許多和 Process 有關的資訊 , ex:Image base / Path..
        *    透過組合語言指令取得: fs:[0x30]
        *    ![](https://i.imgur.com/ASBLDhH.png)
```    
typedef struct _PEB {
+0x000 BOOLEAN InheritedAddressSpace;
+0x001 BOOLEAN ReadImageFileExecOptions;
+0x002 BOOLEAN BeingDebugged; 標誌當前行程是否被Debugger <===== 目標
+0x003 BOOLEAN Spare;
+0x004 HANDLE Mutant;
+0x008 PVOID ImageBaseAddress; 行程的映像地址，預設 exe:0x400000 , dll:0x1000000
+0x00c PPEB_LDR_DATA ldr; 由PE Loader填充，包含很多pe中包含的信息，用來列舉用戶加載的 dll
+0x010 PRTL_USER_PROCESS_PARAMETERS ProcessParameters; 指向 RTL_USER_PROCESS_PARAMETERS 的指標，RTL_USER_PROCESS_PARAMETERS 中是一些行程的參數。
+0x014 PVOID SubSystemData;
PVOID ProcessHeap; 指向行程堆積地址，每個程式新建時預設堆積使用
PVOID FastPebLock; 存放的是PEBLOCKROUTINE這個例程函數需要用到的參數。
PPEBLOCKROUTINE FastPebLockRoutine; PEB加鎖/解鎖回調例程
PPEBLOCKROUTINE FastPebUnlockRoutine;
ULONG EnvironmentUpdateCount; 行程的環境變數更改的次數
PPVOID KernelCallbackTable; 從內核 “回呼” 用戶空間的函數
PVOID EventLogSection;
PVOID EventLog;
PPEB_FREE_BLOCK FreeList;
ULONG TlsExpansionCounter;
PVOID TlsBitmap; 
ULONG TlsBitmapBits[0x2];
PVOID ReadOnlySharedMemoryBase;
...
```


*    reference
        *    [Peb(Process Environment Block)简单学习及分析](http://www.youngroe.com/2015/08/01/Debug/peb-analysis/)


## Anti Debugger Trick
- Trick1:PEB->BeingDebugged / PEB->NtGlobalFlag • 
- Trick2:Enum Process Name 
    - x32dbg.exe / x64dbg.exe 
- Trick3:Enum Process Windows Name 
    - FindWindow(“x64dbg_windows_name”) 
- Trick4:透過時間差來判別 
    - GetTickCount、GetSystemTime、GetLocalTime … 
- Trick5:錯誤的API call 卻回傳正確結果

[自動偵測debuger code](https://hackmd.io/xE5l25jPQs-7oyHKMpk2GA)

## Anti Debugger plugins
- Sharp OD Plugin 
    - https://goo.gl/juzdQ5 
**防止偵測debug，過濾掉API上偵測回傳的數值**
- ScyllaHide Plugin
    - https://github.com/x64dbg/ScyllaHide/releases
**防止偵測debug，過濾掉API上偵測回傳的數值**

> 打一下這兩個是幹嘛的 我沒聽到
> 還有上面那個010 editor回去有空弄成一個一個步驟 乾蝦
> 

## Anti VM Trick
-  Trick1: Vmware IO API 
-  Trick2: Vm Mac Address(固定) 
-  Trick3: Vm Process Name 
    -  Vmtools.exe … 
-  Trick4: Vm File Directory 
    -   C:\ProgramFile\vmware … 
-  Trick5: 奇技淫巧 (anti sandbox) 
    -  桌面檔案數量 
    -  瀏覽器網站數量 
    -  最近訪問檔案數量 
    -   記憶體是否小於或等於 1G 
    -   硬碟容量 <= 100 GB 
-   Anti-vm
```cpp=
//#include "stdafx.h"
#include "windows.h"
#include <iostream> //for c++ string
#include <tlhelp32.h>//for eunmProcess API
#include <tchar.h>
#include "shlwapi.h"


//For Query Mac Address
#include <httpext.h>
#include <windef.h>
#include <nb30.h>
#pragma comment(lib,"netapi32")
#pragma comment(lib,"shlwapi")


using namespace std;


bool Check_VM_MacAddress()
{
	wstring strMac = L"";
	TCHAR mac[20] = { 0 };
	TCHAR check_mac[20] = { 0 };

	NCB ncb;
	typedef struct _ASTAT_
	{
		ADAPTER_STATUS   adapt;
		NAME_BUFFER   NameBuff[30];
	}ASTAT, *PASTAT;

	ASTAT Adapter;

	typedef struct _LANA_ENUM
	{
		UCHAR   length;
		UCHAR   lana[MAX_LANA];
	}LANA_ENUM;

	LANA_ENUM lana_enum;
	UCHAR uRetCode;
	memset(&ncb, 0, sizeof(ncb));
	memset(&lana_enum, 0, sizeof(lana_enum));
	ncb.ncb_command = NCBENUM;
	ncb.ncb_buffer = (unsigned char *)&lana_enum;
	ncb.ncb_length = sizeof(LANA_ENUM);
	uRetCode = Netbios(&ncb);

	if (uRetCode != NRC_GOODRET)
		return false;

	for (int lana = 0; lana < lana_enum.length; lana++)
	{
		ncb.ncb_command = NCBRESET;
		ncb.ncb_lana_num = lana_enum.lana[lana];
		uRetCode = Netbios(&ncb);
		if (uRetCode == NRC_GOODRET)
			break;
	}

	if (uRetCode != NRC_GOODRET)
		return false;

	memset(&ncb, 0, sizeof(ncb));
	ncb.ncb_command = NCBASTAT;
	ncb.ncb_lana_num = lana_enum.lana[0];
	strcpy_s((char*)ncb.ncb_callname, sizeof("*"), "*");
	ncb.ncb_buffer = (unsigned char *)&Adapter;
	ncb.ncb_length = sizeof(Adapter);
	uRetCode = Netbios(&ncb);

	if (uRetCode != NRC_GOODRET)
		return false;

	_stprintf_s(mac, 20, _T("%02x:%02x:%02x:%02x:%02x:%02x"),
		Adapter.adapt.adapter_address[0],
		Adapter.adapt.adapter_address[1],
		Adapter.adapt.adapter_address[2],
		Adapter.adapt.adapter_address[3],
		Adapter.adapt.adapter_address[4],
		Adapter.adapt.adapter_address[5]);

	_stprintf_s(check_mac, 20, _T("%02x-%02x-%02x"), //for check.
		Adapter.adapt.adapter_address[0],
		Adapter.adapt.adapter_address[1],
		Adapter.adapt.adapter_address[2]);

	strMac = check_mac;
	printf("Get local mac address:%ws\n", mac);

	if (strMac == L"00-05-69" || strMac == L"00-0c-29" || strMac == L"00-50-56")//Vmware
	{
		return TRUE;
	}

	if (strMac == L"00-03-ff")//VirtualPC
	{
		return TRUE;
	}

	if (strMac == L"08-00-27")//VirtualBox
	{
		return TRUE;
	}

	return FALSE;
}


BOOL check_VM_EnumprocessName() //https://www.tenouk.com/cpluscodesnippet/listheprocessmodulesinfo.html
{
	HANDLE hProcessSnap;
	PROCESSENTRY32 pe32;

	// Take a snapshot of all processes in the system.
	hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hProcessSnap == INVALID_HANDLE_VALUE)
	{
		return(FALSE);
	}

	// Set the size of the structure before using it.
	pe32.dwSize = sizeof(PROCESSENTRY32);
	// Retrieve information about the first process, and exit if unsuccessful
	printf("\n\n*********************************");
	printf("\nList of process & their info...\n");
	printf("*********************************");
	if (!Process32First(hProcessSnap, &pe32))
	{
		printf("Process32First()"); // Show cause of failure
		CloseHandle(hProcessSnap); // Must clean up the snapshot object
		return (FALSE);
	}

	// Now walk the snapshot of processes, and display information about each process in turn
	do
	{
		printf("\n\n===========================================================");
		printf("\nPROCESS NAME: %S", pe32.szExeFile);
		printf("\n-----------------------------------------------------------");
		printf("\n Parent process ID = %u", pe32.th32ParentProcessID);
		printf("\n Process ID = %u", pe32.th32ProcessID);
		printf("\n Thread count = %u", pe32.cntThreads);

		if (0 == wcscmp(pe32.szExeFile, L"vmtoolsd.exe"))//找到目標
		{
			return TRUE;
		}

	} while (Process32Next(hProcessSnap, &pe32));
	// Don't forget to clean up the snapshot object!
	CloseHandle(hProcessSnap);
	return FALSE;
}


BOOL CheckVMware_with_file_path()
{
	if (PathIsDirectoryA("C:\\Program Files\\VMware\\VMware Tools\\"))//存在時返回TRUE
		return TRUE;

	return FALSE;
}


BOOL CheckVMWare_with_VMapi()
{
	bool rc = true;
	__try
	{
		__asm
		{
			push   edx
			push   ecx
			push   ebx
			mov    eax, 'VMXh'
			mov    ebx, 0
			mov    ecx, 10
			mov    edx, 'VX'
			in     eax, dx
			cmp    ebx, 'VMXh'
			setz[rc]
			pop    ebx
			pop    ecx
			pop    edx
		}
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		rc = false;
	}
	return rc;
}

int main()
{
	if (CheckVMWare_with_VMapi())
	{
		MessageBoxA(NULL, "Check Vm with Vm api", "message", MB_OK);
		ExitProcess(0);
	}

	if (Check_VM_MacAddress())
	{
		MessageBoxA(NULL, "Check Vm with Mac address", "message", MB_OK);
		ExitProcess(0);
	}


	if (check_VM_EnumprocessName())
	{
		MessageBoxA(NULL, "Check Vm with Process Name", "message", MB_OK);
		ExitProcess(0);
	}


	if (CheckVMware_with_file_path())
	{
		MessageBoxA(NULL, "Check Vm with File path", "message", MB_OK);
		ExitProcess(0);
	}


	MessageBoxA(NULL, "Software running~", "message", MB_OK);

	return 0;
}
```

##  Process Explorer
**某知名通訊軟體可用Process Explorer破解多開**
![](https://i.imgur.com/LSKKxeU.png)
- 只要清除圖片上的handle，就可以達成多開

**Line也是一樣的手法**
![](https://i.imgur.com/eSwk6Ml.png)

## Process Hacker = 山寨版Process Explorer

# 軟體自我保護方案
## 字串初階隱藏方法
```
Stack Strings Demo

//#include "stdafx.h"
#include "pch.h"
#include <iostream>

int main()
{
    printf("this is hidden strings Test\n");

    char satack_strings_type1[256] = "this is stack string type1";
    printf("%s\n",satack_strings_type1);

    char stack_strings_type2[256] = {'t' ,'h','i','s','i','s',' ' ,'h','i','d','d','e','n','!' , '\0'};
    printf("%s\n",stack_strings_type2);

    return 0;
}

```
- after shift+F12>x>F5:
![](https://i.imgur.com/adaLT0G.png)
- after Deciaml -> Char
![](https://i.imgur.com/ms25kki.png)

## 字串編譯時期加密
- after shift+F12>x>F5:
![](https://i.imgur.com/GEpe6ky.png)
- after Deciaml -> Char
![](https://i.imgur.com/rUZND6F.png)



## 加殼技術介紹與運用
- 加殼技術是一種對 PE 檔案的資料壓縮及加密保護，可以將 PE 檔案 壓縮成自我解壓檔案，並不會讓使用者能感覺出解壓過程
- 用途： 
    - 減少檔案大小：可節省磁碟空間、加速網路傳輸 
    - 加密內容：可以避免程式遭到任意竄改 
    - 授權機制：不須自行撰寫授權機制 , 殼已經實作完成 , 套用SDK即可產生授權
- 示意圖
![](https://i.imgur.com/d6Obdi4.png) 
### UPX 壓縮殼使用 
![](https://i.imgur.com/6L4pDEk.png)
![](https://i.imgur.com/VTaPSBB.png)

### 動態跟蹤 UPX 解殼過程 
### Vmprotect殼的正確 SDK 使用方式
- vmmap(看記憶體分布)
![](https://i.imgur.com/rWWmUOk.png)
![](https://i.imgur.com/bIxiGqR.png)
虛擬化

字串尚未保護
![](https://i.imgur.com/PDukiR8.png)
- 在VMProtectBegin()和VMProtectEnd()中間加上VmProtectDecryptA
![](https://i.imgur.com/vh6Tlkz.png)

## 手動體驗加殼過程
- x64dbg/pelord/010editor

## 手動體驗加殼過程
- x64dbg > 外掛程式(scylla) > IAT search > Get Import > Dump > Fix Dump

# 斷點的原理與背後的秘密
![](https://i.imgur.com/INwxvbm.png)
**軟體斷點**
- 配合Cheat Engine測試
**記憶體斷點**
- 配合VMmap 測試
**硬體斷點**
- 配合x64dbg測試
![](https://i.imgur.com/q1E48q6.png)
![](https://i.imgur.com/iNcRB1p.png)
![](https://i.imgur.com/fETok9W.png)


# 神奇妙用 無痕的 Memory Hijack
![](https://i.imgur.com/wTzxIH4.png)

# Anti Memory Pached
```cpp=
// GetWriteWatch Trick
//#include "pch.h"
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <stdio.h>

//假設的重要資料 (人物座標)
typedef struct _POSITION_
{
	DWORD dx;
	DWORD dz;
	DWORD dy;
}POSITION, *PPOSITION;

#define BASE_SIZE 0x1000
#define WALK_ADD 10
DWORD WINAPI WatchThread(LPVOID Param)
{
	ULONG dwPageCount = 0;
	DWORD page_size = 0;
	UINT  Ret = 0;
	PVOID lpAddresses[BASE_SIZE] = { 0 };
	while (TRUE)
	{
		dwPageCount = BASE_SIZE;
		page_size = 0;
		Ret = GetWriteWatch(WRITE_WATCH_FLAG_RESET, Param, BASE_SIZE, lpAddresses, &dwPageCount, &page_size);
		//printf("ret:%d lpdwCount:%d page_size:%d\n", Ret, dwPageCount, page_size);
		if (Ret == ERROR_SUCCESS && dwPageCount != 0)
		{
			MessageBoxW(NULL, L"偵測記憶體被修改!!!", L"發現異常", MB_OK);
		}

		Sleep(100);
	}
	return 0;
}
int __cdecl main(int argc, char *argv[])
{
	PVOID Base = VirtualAlloc(NULL, BASE_SIZE, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE); // MEM_WRITE_WATCH is importment.
	printf("Watch Address:0x%x\n", Base);

	PPOSITION pos = (PPOSITION)Base;
	//初始化座標
	pos->dx = pos->dy = pos->dz = 1000;
	//清除監控記錄
	ResetWriteWatch(Base, BASE_SIZE);
	//開啟監控執行緒
	HANDLE hThread = CreateThread(NULL, 0, WatchThread, Base, 0, NULL);
	while (1)
	{

		//模擬外掛走路過程 , [修改記憶體]
		//pos->dx += WALK_ADD;

		//輸出 X 座標
		printf("x = %d\n", pos->dx);
		Sleep(1000);
	}
	return 0;
}
```

# Malware 匿蹤與控制技術研究
## Autorun 持久化控制
- 防毒軟體永遠的痛 DLL Side Loading
    - [Github](https://github.com/KennyZeng/signed-loaders)
    - 利用程式讀取DLL的漏洞，置換有惡意shellcode的DLL檔變成病毒
    - 怎麼發現呢？ 用ProcessMonitor去看會不會讀當前路徑的DLL檔
- 通用且隱蔽的 Autorun 方法 IAT Hijacking




## 6 2 Shellcode 快速開發技巧
- How to GetProcAddress like a boss 😎
- PE To Shellcode
    - [pe2shc](https://github.com/KennyZeng/pe_to_shellcode)
    - 直接把程式轉成shellcode，再搭配shellcode loader繞過防毒軟體檢測(processname不會顯示shellcode的程式名稱)