[工控安全][原創]SIEMENS SIMATIC STEP7軟件中關鍵DLL文件分析(一)

mailto:wangkai0351@gmail.com
【未經贊成禁止轉載】git

賽門鐵克的震網STUXNET病毒分析報告中聲稱,github

震網病毒是替換掉Step7軟件中S7OTBXDX.DLL動態連接庫文件,該DLL文件包含了一些對PLC編程和調試有關鍵功能的函數,好比編程

  • s7db_open and s7db_close
  • s7ag_read_szl
  • s7_event
  • s7ag_test
  • s7ag_link_in
  • s7ag_bub_cycl_read_create
  • s7ag_bub_read_var
  • s7ag_bub_write_var
  • s7ag_bub_read_var_seg
  • s7ag_bub_write_var_seg

programm files/system路徑下找到了這個文件,可是Step7軟件的用戶協議中禁止了對其進行逆向分析數組

被許可方無權對軟件進行修改、反編譯或逆向工程。並且也不能提取任何單獨的部分,除非強制的版權法容許。網絡

這樣,咱們沒有權利反編譯它了。可是有權調試它?函數

**(諮詢西門子中國工業客戶服務中心,得知包括使用ollydbg和windbg在內的工具對工程軟件後臺運行的探測行爲,屬於*《用戶協議》中"逆向工程」範疇)**工具

我仍是從網絡上找到了一些蛛絲馬跡,好比著名的逆向分析S7comm協議的成果——LIBNODAVE開源軟件(github地址)中調用了Step7的另外一個DLLS7ONLINX.DLL指針

LIBNODAVE調用了S7ONLINX.DLL其中的幾個函數(或者稱它們爲SCP_函數簇,經過串口走S7comm on MPI協議)調試

SCP_opencode

SCP_close

SCP_get_errno

SCP_send

SCP_receive

SetSinecHWnd

具體的調用方式的代碼以下

EXPORTSPEC HANDLE DECL2 openS7online(const char * accessPoint, HWND handle) {
    HMODULE hmod;
    int h,en;
    _setHWnd SetSinecHWnd; 

    hmod=LoadLibrary("S7onlinx.dll");
    if (daveDebug & daveDebugOpen)
    LOG2("LoadLibrary(S7onlinx.dll) returned %p)\n",hmod);

    SCP_open=GetProcAddress(hmod,"SCP_open");
    if (daveDebug & daveDebugOpen)
        LOG2("GetProcAddress returned %p)\n",SCP_open);

    SCP_close=GetProcAddress(hmod,"SCP_close");
    if (daveDebug & daveDebugOpen)
    LOG2("GetProcAddress returned %p)\n",SCP_close);

    SCP_get_errno=GetProcAddress(hmod,"SCP_get_errno");
    if (daveDebug & daveDebugOpen)
    LOG2("GetProcAddress returned %p)\n",SCP_get_errno);

    SCP_send=GetProcAddress(hmod,"SCP_send");
    if (daveDebug & daveDebugOpen)
    LOG2("GetProcAddress returned %p)\n",SCP_send);

    SCP_receive=GetProcAddress(hmod,"SCP_receive");
    if (daveDebug & daveDebugOpen)
    LOG2("GetProcAddress returned %p)\n",SCP_receive);
    
    SetSinecHWnd=GetProcAddress(hmod,"SetSinecHWnd");
    if (daveDebug & daveDebugOpen)
    LOG2("GetProcAddress returned %p)\n",SetSinecHWnd);

    en=SCP_get_errno();
    h=SCP_open(accessPoint);
    en=SCP_get_errno();
    LOG3("handle: %d  error:%d\n", h, en);
    SetSinecHWnd(h, handle);
    return h;
};

EXPORTSPEC HANDLE DECL2 closeS7online(int h) {
    SCP_close(h);
}

調用上述代碼中定義的openS7online函數和closeS7online函數的方式可參考testS7online.c文件

fds.rfd=openS7online(argv[adrPos], GetConsoleHwnd());//第二個參數是綁定到一個窗口上
closeS7online(fds.rfd);

能夠看出,調用openS7online函數只是把SCP_函數簇加載到或者說注入到進程的內存空間中,像SCP_open就至關於這個函數在當前進程中的函數入口地址了,因此在main函數開頭解析完調輸入參數後就要調用,其第一個參數argv[adrPos]是一個字符串指針,表明access point,也就是上位機串口的接入點;第二個參數,是綁定到執行main函數當前的窗口。

當前,已經把SCP_函數簇加載到內存空間中了,下面咱們接着看testS7online.c文件是如何調用SCP_函數簇經過串口發送報文數據的。咱們的目的是,瞭解SCP_函數簇的輸入和輸出參數是什麼?

nodave.c文件中,經過分別包裝SCP_sendSCP_receive寫了兩個函數。

先看SCP_send函數

//nodave.c
int DECL2 _daveSCP_send(int fd, uc * reqBlock) {
    S7OexchangeBlock* fdr;
    fdr=(S7OexchangeBlock*)reqBlock;
    fdr->headerlength=80;
    fdr->allways2 = 2;
    fdr->payloadStart= 80;
    return SCP_send(fd, fdr->payloadLength+80, reqBlock);
}

能夠看到給SCP_send函數傳遞了三個參數,分別是

類型 說明(本身胡猜)
int 發送報文使用串口的地址
uc/unsigned char 發送報文長度,具體報文的結構定義還不肯定
uc/unsigned char 發送報文數組的其實地址

函數返回類型是int,本身胡猜,多是函數執行成功否?

再看SCP_receive函數

//nodave.c
int daveSCP_receive(int h, uc * buffer) {
    int res, datalen;
    S7OexchangeBlock * fdr;
    fdr=(S7OexchangeBlock*) buffer;
    res=SCP_receive(h, 0xFFFF, &datalen, sizeof(S7OexchangeBlock), buffer);
    if (daveDebug & daveDebugByte) {
    _daveDump("header:",buffer, 80);
    _daveDump("data:",buffer+80, fdr->payloadLength);
    _daveDump("data:",buffer+80, fdr->payloadLength);
    }   
    return res; 
}

能夠看到給SCP_receive函數傳遞了五個參數,分別是

類型 說明(本身胡猜)
int 接收報文使用串口的地址(一般狀況下和發送報文用一個串口?)
int 0xFFFF定值?
*int 接收報文的長度
int S7OexchangeBlock是s7onlinx.dl和其調用者之間交換數據塊的結構體
uc/unsigned char 接收報文數據的起始地址

返回參數是int,本身胡猜,多是函數執行成功否?

至今,咱們以LIBNODAVE開源軟件瞭解了STEP7的一個DLL文件中兩個關鍵函數的接口,以及研究者本身如何調用該DLL中的兩個函數,以近乎黑盒的形式研究這些函數。

相關文章
相關標籤/搜索