偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

使用Frida在Windows中攔截C++函數(shù)

開(kāi)發(fā) 前端
使用Frida可以訪問(wèn)目標(biāo)進(jìn)程的內(nèi)存空間,在目標(biāo)程序運(yùn)行時(shí)可以覆蓋一些功能,從導(dǎo)入的類(lèi)中調(diào)用函數(shù),在堆上可以查找對(duì)象實(shí)例并使用這些對(duì)象實(shí)例,并可以Hook、跟蹤和攔截函數(shù)等等。

1.摘要

Frida是一款基于Python+javascript的Hook框架, 可運(yùn)行在Windows、Android、iOS、Linux、MacOS全平臺(tái)系統(tǒng)中,主要使用了動(dòng)態(tài)二進(jìn)制插樁技術(shù)。插樁技術(shù)是指將額外的代碼注入到目標(biāo)程序中, 以實(shí)現(xiàn)收集目標(biāo)運(yùn)行時(shí)信息, 插樁技術(shù)主要分為兩種:源代碼插樁和二進(jìn)制插樁, 源代碼插樁是將額外代碼注入到程序源代碼中,二進(jìn)制插樁是將額外代碼注入到二進(jìn)制可執(zhí)行文件中。

使用Frida可以訪問(wèn)目標(biāo)進(jìn)程的內(nèi)存空間,在目標(biāo)程序運(yùn)行時(shí)可以覆蓋一些功能,從導(dǎo)入的類(lèi)中調(diào)用函數(shù),在堆上可以查找對(duì)象實(shí)例并使用這些對(duì)象實(shí)例,并可以Hook、跟蹤和攔截函數(shù)等等。

2.Frida的能力

Frida是一個(gè)非常強(qiáng)大的動(dòng)態(tài)instrumentation框架,其主要能力包括:

  • 攔截(Hook)系統(tǒng)API調(diào)用:可以hook目標(biāo)程序的各種系統(tǒng)API調(diào)用,如文件、網(wǎng)絡(luò)、進(jìn)程、加密等,攔截和修改參數(shù)或返回值。
  • 注入JS代碼:可以實(shí)時(shí)向目標(biāo)程序注入JavaScript代碼,調(diào)用其函數(shù)接口或修改程序運(yùn)行邏輯。
  • 動(dòng)態(tài)調(diào)試:可以動(dòng)態(tài)地設(shè)置斷點(diǎn)、Dump內(nèi)存、遍歷對(duì)象等,無(wú)需重啟程序。
  • 反混淆和脫殼:可以通過(guò)dump內(nèi)存或hook相關(guān)函數(shù)的方式對(duì)加殼/混淆的目標(biāo)程序進(jìn)行反混淆和脫殼。
  • 適用范圍廣:支持Windows、Linux、macOS、iOS、Android等主流平臺(tái)。
  • 多語(yǔ)言綁定:提供Java、Python、C#等語(yǔ)言的綁定庫(kù), 可以使用腳本語(yǔ)言進(jìn)行交互。
  • 插件機(jī)制:支持?jǐn)U展自己的插件,實(shí)現(xiàn)自定義功能。
  • 開(kāi)源免費(fèi):Frida是完全開(kāi)源免費(fèi)的,社區(qū)活躍。

3.Frida常用語(yǔ)法

Frida在實(shí)戰(zhàn)使用過(guò)程中,經(jīng)常使用的功能語(yǔ)法主要包括以下這些:

導(dǎo)入frida模塊:

const frida = require('frida');

附加/注入進(jìn)程:

// 附加
const session = await frida.attach(pid);

// 注入
const session = await frida.spawn([path], options);

創(chuàng)建/加載/卸載腳本實(shí)例:

# 創(chuàng)建
const script = await session.createScript(source);

# 加載
await script.load();

# 卸載
await script.unload();

導(dǎo)出函數(shù):

rpc.exports = {
   func1: (args) => {
      // ...
   }
}

Hook函數(shù):

Interceptor.attach(target, {
  onEnter: function(args) {
    
  },
  
  onLeave: function(retval) {
  }
});

讀寫(xiě)內(nèi)存:

let buf = Memory.readByteArray(addr, len);
Memory.writeByteArray(addr, [1, 2, 3]);

枚舉/搜索模塊:

// 枚舉
Process.enumerateModules()

// 搜索
Process.findModuleByName()

枚舉/搜索導(dǎo)出函數(shù):

// 枚舉
Module.enumerateExports()

// 搜索
Module.findExportByName()

調(diào)用函數(shù):

let retval = Module.getExportByName()(args);

4.Frida安裝

這里以Windows10環(huán)境為基礎(chǔ)進(jìn)行實(shí)驗(yàn), 首先在Windows搜索框中搜索:PowerShell, 以管理員權(quán)限打開(kāi), 并執(zhí)行以下命令:

pip install frida-tools

注意:這里一定要以管理員權(quán)限打開(kāi)PowerShell,否則可能會(huì)安裝失敗。

安裝成功后如圖所示:

圖片圖片

輸入命令frida --version 查看Frida的版本號(hào),如果正常顯示版本號(hào),則說(shuō)明安裝成功, 如圖:

圖片圖片

5.編寫(xiě)測(cè)試程序

編寫(xiě)測(cè)試程序的目的是要驗(yàn)證Frida能否成功Hook測(cè)試程序中的指定函數(shù), 并將函數(shù)的每個(gè)參數(shù)內(nèi)容進(jìn)行打印。

我在這里的測(cè)試程序使用C++編寫(xiě), 主要完成2個(gè)函數(shù), AES加密和解密算法, 設(shè)想的步驟是將AES加密算法和解密算法的兩個(gè)函數(shù)編譯成Dll,并將兩個(gè)函數(shù)導(dǎo)出, 然后再寫(xiě)一個(gè)客戶(hù)端程序加載Dll并調(diào)用導(dǎo)出函數(shù)。

AES加密算法的C++代碼如下:

extern "C"  __declspec(dllexport) void AesEncrypt(unsigned char* plaintext, int plaintext_len, unsigned char* key, unsigned char* iv,
    unsigned char* ciphertext) {
    EVP_CIPHER_CTX* ctx;
    int len;
    int ciphertext_len;

    printf("AesEncrypt is at %p\n", AesEncrypt);

    ctx = EVP_CIPHER_CTX_new();

    EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);

    EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len);
    ciphertext_len = len;

    EVP_EncryptFinal_ex(ctx, ciphertext + len, &len);
    ciphertext_len += len;

    EVP_CIPHER_CTX_free(ctx);
}

AES加密算法函數(shù)AesEncrypt包含了四個(gè)參數(shù),分別為: 明文字符串、明文字符串長(zhǎng)度、Key、iv向量。

AES解密算法C++代碼如下:

// AES解密
extern "C"  __declspec(dllexport) void AesDecrypt(unsigned char* ciphertext, int ciphertext_len, unsigned char* key, unsigned char* iv,
    unsigned char* plaintext) {
    EVP_CIPHER_CTX* ctx;
    int len;
    int plaintext_len;

    printf("AesDecrypt is at %p\n", AesDecrypt);

    ctx = EVP_CIPHER_CTX_new();
    EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
    EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len);
    plaintext_len = len;

    EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
    plaintext_len += len;

    EVP_CIPHER_CTX_free(ctx);
}

同樣,AES解密算法函數(shù)AesDecrypt也提供了四個(gè)參數(shù),分別為:密文文本、密文文本長(zhǎng)度、Key、iv向量。

重新建立一個(gè)新的C++工程, 這里模擬了真實(shí)程序的業(yè)務(wù)場(chǎng)景,對(duì)明文字符串使用AES算法加密,為了防止程序運(yùn)行太快退出,這里將主要程序邏輯放到一個(gè)while循環(huán)中,并使用暫停功能進(jìn)行控制,方便后面的函數(shù)Hook實(shí)驗(yàn)。為了方便操作, 我在中間插入了pause暫停, 方便后面手動(dòng)控制函數(shù)的調(diào)用時(shí)機(jī)。

應(yīng)用代碼如下:

typedef void(__stdcall* AES_ENCRYPT_TYPE)(unsigned char*, int, unsigned char*, unsigned char*,
    unsigned char*);

typedef void(__stdcall* AES_DECRYPT_TYPE)(unsigned char*, int, unsigned char*, unsigned char*,
    unsigned char*);

int main()
{
    while (1) {
        //std::cout << "Hello World!\n";
    //原文
        unsigned char plaintext[] = "This is a plaintext message";

        // 密鑰
        unsigned char key[32] = "suntiger20232021sdvdiuyt657uhjg";

        // 初始化向量
        unsigned char iv[16] = "9876kvdfdkkdfdf";

        // 密文緩沖區(qū)
        unsigned char ciphertext[128];

        memset(ciphertext, 0, 128);

        // 加密
        AesEncrypt(plaintext, strlen((char*)plaintext), key, iv, ciphertext);
        system("pause");

        unsigned char decryptedtext[128];
        memset(decryptedtext, 0, 128);
        AesDecrypt(ciphertext, strlen((char*)ciphertext), key, iv, decryptedtext);

        printf("%s\n", decryptedtext);

        system("pause");

        Sleep(1);
    }
}

將以上代碼編譯執(zhí)行后,每按一次空格鍵, 程序便會(huì)依次向下執(zhí)行, 如圖:

圖片圖片

6.編寫(xiě)插樁程序

插樁程序代碼由Python和Javascript語(yǔ)言組合而成,功能非常強(qiáng)大, 以下代碼是我自己實(shí)現(xiàn)的對(duì)動(dòng)態(tài)鏈接庫(kù)中的導(dǎo)出函數(shù)AesEncrypt進(jìn)行Hook,建立一個(gè)Python工程,代碼如下:

import frida
import sys


def on_message(message, data):
    print(message)


# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    local = frida.get_local_device()
    // 附加進(jìn)程
    session = local.attach("test.exe")
    script = session.create_script("""
        var baseAddr = Module.findBaseAddress('aes.dll');
        // 查找函數(shù)模塊
        var aesEncryptAddr = Module.findExportByName("aes.dll", "AesEncrypt");
        Interceptor.attach(aesEncryptAddr, {
        onEnter: function(args) {
            send(args[0]);
            console.log('');
            console.log('[+]plaintext: ' + Memory.readUtf8String(args[0]));
            console.log('[+]plaintext len: ' + args[1].toInt32());
            console.log('[+]key:' + Memory.readUtf8String(args[2]));
            console.log('[+]iv:' + Memory.readUtf8String(args[3]));
        }
    });
    """)

    script.on('message', on_message)
    script.load()
    sys.stdin.read()
    session.detach()

在上面的Hook代碼中,我主要完成了以下操作:

  • 通過(guò)frida在本地查找進(jìn)程test.exe,也就是我上面實(shí)現(xiàn)的客戶(hù)端測(cè)試程序進(jìn)程。
  • 通過(guò)Javascript腳本在進(jìn)程中查找模塊aes.dll, 這個(gè)動(dòng)態(tài)鏈接庫(kù)是我上面實(shí)現(xiàn)的AES加解密測(cè)試程序。
  • 在動(dòng)態(tài)鏈接庫(kù)中查找導(dǎo)出函數(shù)AES加密函數(shù):AesEncrypt,并附加到該函數(shù)地址進(jìn)行參數(shù)監(jiān)控。
  • 打印每個(gè)參數(shù)的內(nèi)容。

以下是我執(zhí)行插樁程序后,獲取到的參數(shù)內(nèi)容,如圖:

圖片圖片

可以看到,已經(jīng)成功把解密函數(shù)的四個(gè)參數(shù)全部打印出來(lái), C++函數(shù)Hook成功。

責(zé)任編輯:武曉燕 來(lái)源: 二進(jìn)制空間安全
相關(guān)推薦

2011-08-22 17:13:00

LuaC++函數(shù)

2010-01-27 17:16:52

C++構(gòu)造函數(shù)

2010-01-26 10:42:26

C++函數(shù)

2009-04-14 14:53:06

C++Lambda函數(shù)多線(xiàn)程

2023-09-26 22:37:16

C++const

2023-04-03 07:08:28

C++函數(shù)模板

2010-02-02 13:15:00

C++ lambda函

2010-01-11 15:29:13

引用C++語(yǔ)言

2010-01-25 09:50:58

C++函數(shù)對(duì)象

2010-01-19 13:43:59

C++函數(shù)

2010-01-25 14:00:27

C++類(lèi)

2010-01-27 10:13:22

C++類(lèi)對(duì)象

2021-04-01 11:28:44

C++ LinuxWindows

2023-09-12 07:38:36

C++getline函數(shù)

2010-03-10 19:18:10

Python scri

2010-01-27 14:00:50

CC++運(yùn)行環(huán)境

2010-02-02 17:39:31

C++構(gòu)造函數(shù)

2010-02-04 16:39:26

C++析構(gòu)函數(shù)

2011-07-13 11:34:58

CC++時(shí)間函數(shù)

2012-04-28 15:28:21

JNI混合編程Java
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)