1. 程式人生 > >發一個自己寫的抓包軟體,支援外掛化指令碼分析

發一個自己寫的抓包軟體,支援外掛化指令碼分析

市場上的抓包工具已經足夠多,輕量級的,重量級的都有,典型的wireshark,smartsniff等,

各有優缺點,PowerSniff是為程式設計師準備的一款抓包工具,目標是使協議解析外掛編寫更簡單。檔案格式完全相容wiareshark和tcpdump。

原理:捕獲到資料就呼叫預設定的指令碼,將資料的指標和長度傳遞給指令碼分析,在指令碼中也支援呼叫註冊函式。

無需編譯,支援即寫即用,目前支援c語言和lua兩種程式語言作為指令碼,安裝檔案自帶一些例子,歡迎測試並提供意見。

一、典型場景

抓包軟體執行時(或事後分析),希望對每個資料包使用外掛分析,smartsniff直接不支援,而wireshark編寫外掛成本太大,

需要安裝visual studio和相關sdk,不論是外掛本身的開發還是除錯,都不是一件簡單的事。

一些廠商對常見的協議(如rtsp),做了wireshark的外掛,但是如果是自己的協議,只能手工分析。

PowerSniff是為快速解決資料分析而來,(即便不考慮資料分析,介面和可操作性也比wireshark, smartsniff更友好),

對捕獲的網路資料包,即時指令碼編寫(語法高亮,即時編譯,即時執行,也可以直接用編寫好的指令碼),

目前指令碼支援lua和c語言,實測在i7上單核處理簡單指令碼外掛呼叫,lua每秒1萬次,c語言更快。

示例:QQ使用UDP協議,伺服器埠8000,登入包的第49位元組到53位元組是qq號,解析並顯示這個qq號

int handle_data(const char *protocol, unsigned char *data, int total_len, int data_len)
{
	unsigned int qq_number = data[49] * 256 * 256 * 256 + data[50] * 256 * 256 + data[51] * 256 + data[52];
	plugin_summary("debug-%d, qq_number is: %d", __LINE__, qq_number);

	return 0;
}

將上面程式碼儲存為test1.c,然後再選單的外掛列表裡面啟用它即可。程式碼不需要編譯

,程式內建的TCC引擎會自動compile,然後relocate到當前程序。

等價於將c語言作為指令碼,由於程式碼只在load時編譯,所以外掛執行速度非常快。(除了c語言支援,另外還支援lua指令碼)

二、相關介面截圖

(1)選單

 

(2)設定

(3)lua編輯器

(4)c語言編輯器

(5)hex顯示介面

(6)安裝檔案列表

(7)第三方外掛xtrace

這個軟體預計下週單獨釋出,目前PowerSniff已經整合c++的sdk。

xtrace程式提供了sdk函式xtrace(),可以看成一個printf函式(支援本機和網路),只是它的輸出不是stdout,而是xtrace軟體。

c++的版本只需要包含一個20k自己的標頭檔案即可,不需要包含lib。另外也支援lua,python,javascript,c#,delphi等語言。

除了printf ,還支援xcounter功能,方便程式效能分析或計數用。(支援本機和網路)

c++最簡用法:

#include "xtrace.h"

xtrace(_T("hello, %s, %d\n"), _T("world"), 99999999);

不需要其它任何改動,直接替換vc裡面的TRACE巨集,或者printf函式。開啟xtrace主程式,即可看到相關輸出。

三、外掛編寫說明(檔案編碼必須使用utf8)

程式需要呼叫的lua介面,參考plugin/demo_lua.lua(1)init: 外掛初始化(2)handle_data: 當收到一個數據包時呼叫這個函式,函式return "delete"也可以起到過濾作用(3)handle_click:當單擊列表資料時呼叫這個函式(4)handle_double: 當雙擊列表資料時呼叫這個函式

lua中增加的可以回撥的程式介面:plugin_output_clear: 清空plugin output視窗plugin_output: 輸出到plugin output視窗plugin_summary: 輸出到listview最右邊的Plugin Summary項trace: 輸出到三方工具xtracetrace_raw: 輸出到三方工具xtrace

dbgview:輸出到三方工具dbgview.exe

------------------------------------------------------------

c語言自定義函式參考:bin\3rd\libtcc\include\powersniff.h

#ifndef __POWERSNIFF_DEFINE_H_
#define __POWERSNIFF_DEFINE_H_

int trace(const char *format, ...);
int TRACE(const char *format, ...);
int xtrace(const char *format, ...);
int XTRACE(const char *format, ...);

int trace_raw(int color, const char *format, ...);
int TRACE_RAW(int color, const char *format, ...);
int xtrace_raw(int color, const char *format, ...);
int XTRACE_RAW(int color, const char *format, ...);


int dbgview(const char *format, ...);
int DBGView(const char *format, ...);

int plugin_output(const char *format, ...);
int PLUGIN_OUTPUT(const char *format, ...);

int plugin_output_clear();
int PLUGIN_OUTPUT_CLEAR();

int plugin_summary(const char *format, ...);
int PLUGIN_SUMMARY(const char *format, ...);
#endif

解析qq號的lua指令碼:

-- file encode must be UTF8
-- qq號碼登入監視指令碼(不支援手機號碼登入,不支援webqq,只在pc上用qq2015測試通過)
-- 2015.9.14
require "base64"
require "tcp_ip"

function init()
    trace("plugin init:  ".._VERSION.."\n")
    trace("package path: "..package.path.."\n")
    trace("package path: "..package.cpath.."\n")
    --for k,v in pairs(_G) do
    --    trace(string.format("%s,%s\n", k, v))
    --end
end

-- protocol:    字串如tcp,udp,icmp
-- data:    二進位制資料
-- len_total:    總共資料長度
-- len_data:    有效資料長度(去除各種頭之後的資料)
function handle_data(protocol,data,len_total,len_data)
    if 54 == len_total then
        return "delete"        -- remove handshake
    end
    src_port = tcp_ip_get_src_port(data)
    dst_port = tcp_ip_get_dst_port(data)
    -- if 8000 != src_port && 8000 != dst_port then
    if (8000 ~= dst_port) or (len_data < 100) then
        return "delete"
    end
    if 2 ~= data:byte(43) then    -- 0x2是qq udp協議magic number
        return "delete"
    end
    if 8 ~= data:byte(46) then    -- 8和37是 0x8和0x25是協議型別,表示登入
        return "delete"
    end
    if 37 ~= data:byte(47) then
        return "delete"
    end
    -- 50, 51, 52, 53位元組是qq號(lua index從1開始而不是0)
    qq_number = data:byte(50) * 256 * 256 * 256 + data:byte(51) * 256 * 256 + data:byte(52) * 256 + data:byte(53)
    plugin_summary("qq_number is: " .. qq_number)
end

function handle_click(protocol,data,len_total,len_data)
    if 54 == len_total then
        return
    end
    src_port = tcp_ip_get_src_port(data)
    dst_port = tcp_ip_get_dst_port(data)
    -- if 8000 != src_port && 8000 != dst_port then
    if (8000 ~= dst_port) or (len_data < 100) then
        return
    end
    if 2 ~= data:byte(43) then    -- 0x2是qq udp協議magic number
        return 
    end
    if 8 ~= data:byte(46) then    -- 8和37是 0x8和0x25是協議型別,表示登入
        return
    end
    if 37 ~= data:byte(47) then
        return
    end
    -- 50, 51, 52, 53位元組是qq號(lua index從1開始而不是0)
    qq_number = data:byte(50) * 256 * 256 * 256 + data:byte(51) * 256 * 256 + data:byte(52) * 256 + data:byte(53)
    plugin_output_clear()
    plugin_output("qq_number is: " .. qq_number.."\n")
end

function handle_double(protocol,data,len_total,len_data)
    handle_data(protocol,data,len_total,len_data)
end

解析qq號的c指令碼:

// file encode must be UTF8
// sdk function:
// init()        
// handle_data()    
// handle_click()    
// handle_double()
// all data lock at background, you can use pointer any case,  but need ATTENTION also.
// out of memory or invalid pointer may crash the full virutal machine, or cause application fetal error.
// the follow thread .h file should include!
#include <winapi\windows.h>
#include <winapi\wingdi.h>
#include <powersniff.h>

void init()
{
    trace_raw(RGB(255, 0, 0), "do init here\n");
}

// if return -1, the packet will be deleted!
int handle_data(const char *protocol, unsigned char *data, int total_len, int data_len)
{
    if(0 != strcmp("udp", protocol)) {
        return -1;        // filter
    }

    if(data_len < 100) {
        return -1;        // filter
    }

    short src_port = data[34] * 256 + data[35];
    short dst_port = data[36] * 256 + data[37];
    if(8000 != dst_port)
        return -1;

    if(2 != data[42])        // 0x2是qq udp協議magic number
        return -1;
    if(8 != data[45])        // 8和37是 0x8和0x25是協議型別,表示登入
        return -1;
    if(37 != data[46])
        return -1;

    unsigned int qq_number = data[49] * 256 * 256 * 256 + data[50] * 256 * 256 + data[51] * 256 + data[52];
    plugin_summary("debug-%d, qq_number is: %d", __LINE__, qq_number);
    plugin_output_clear();
    plugin_output("debug-%d, qq_number is: %d\n", __LINE__, qq_number);
    trace("debug-%d, qq_number is: %d\n", __LINE__, qq_number);
    return 0;
}

// fixed return 0
int handle_click(const char *protocol, unsigned char *data, int total_len, int data_len)
{
    trace_raw(RGB(0, 0, 255), "blue output\n");
    return 0;
}

// fixed return 0
int handle_double(const char *protocol, unsigned char *data, int total_len, int data_len)
{
    trace("default color output\n");
    trace_raw(RGB(0, 0, 255), "blue output\n");
    dbgview("output to debugview.exe\n");
    
    plugin_summary("hello1: %d", 123);
    plugin_output_clear();
    plugin_output("hello2: %d", 123);
    plugin_output_clear();
    plugin_output("hello3: %d\n", 456);
    plugin_output("hello4: %d\n", 789);
    return 0;
}

void *my_memcpy(void * to, const void * from, int n)
{
int d0, d1, d2;
__asm__ __volatile__(
        "rep ; movsl\n\t"
        "testb $2,%b4\n\t"
        "je 1f\n\t"
        "movsw\n"
        "1:\ttestb $1,%b4\n\t"
        "je 2f\n\t"
        "movsb\n"
        "2:"
        : "=&c" (d0), "=&D" (d1), "=&S" (d2)
        :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
        : "memory");
return (to);
}

四、其它抓包工具

重量級抓包工具:wireshark(推薦);科來網路分析軟體;ominipeek;etherpeek;Charles;(經過各種測試,還是wireshark最好用)

輕量級抓包工具:smartsniff:只有230KB(推薦);minisniff:只有45KB(2006年停止維護);powersniff:2.3M(包含若干個第三方外掛)

五、閉源。非商業使用無限制。收到BUG會解決(反饋qq群466507719)。無其它技術支援。

付費封閉協議分析及定製指令碼。目前只支援ipv4(tcp,udp,icmp),已對pcap數十個樣本測試,如需要其它協議可以定製。

六、借地找個工作,地點武漢光谷~~~

目標嵌入式,c++,伺服器端開發,移動端或web開發等軟體工作;也可以偏管理;

對web開發較有興趣,熟練的同學可以技能交換

(只收3year+的同學,不閒聊,武漢光谷有定期線下交流,最好能提供一份帶詳細專案經驗的簡歷,qq:80101277)

擁劍,中南民族大學附近2018.10.12