用于整人用的,立刻掛斷時阿里通不收費。
流程:寫程序向客戶端發送消息,實現撥號功能;修改客戶端,方便我們的程序獲知對方正在響鈴,然后立刻掛斷。
一、文件脫殼 客戶端加了個ASPACK 2.12的殼
(1)先清除ASLR標記(ASLR用于隨機程序載入基地址,最好先清除掉)
(2)直接使用脫殼機脫殼。
二、自動撥號功能
原理:自動撥號,很自然的思路就是把子窗體控件找出來,然后從外部發送消息過來,實現按鈕點擊。
(1)原先的思路是使用spy++把子控件都找出來,但是分析發現阿里通使用了第三方UI庫(SOUI),SPY++什么都找不到。
(2)那就直接調試——產生按鍵的消息找出來。
直接拉入OD,直接在API DispatchMessage()中設置消息條件斷點,攔截單擊釋放事件。
攔截條件為:[[esp+4]+4]==WM_LBUTTONUP,即左鍵單擊釋放事件。很快斷下來了。可以發現這個UI庫是通過事件
發生時的坐標軸(即消息結構體的LPARAM)來辨別是哪個按鍵被單擊的,所以找到所有的數字按鍵的lparam參數,直接記錄
下來,之后只要發送WM_LBUTTONUP消息給主窗口,填充下lparam參數就行了,宏定義如下:
- //找到的lparam參數如下
- #define BTN_1 0x010d01d1
- #define BTN_2 0x010d0221
- #define BTN_3 0x010d0301
- #define BTN_4 0x014d01d1
- #define BTN_5 0x014d0221
- #define BTN_6 0x014d0301
- #define BTN_7 0x018d01d1
- #define BTN_8 0x018d0267
- #define BTN_9 0x018d0301
- #define BTN_0 0x01bd0267
- #define BTN_BACKSPACE 0x009c02f1 //回退按鈕
- #define BTN_CALL 0x02320260 //撥打按鈕
- #define BTN_STOP 0x01db02c1 //掛斷按鈕
- #define BTN_DIAL_PAGE 0x00AB0024 //播放頁面
三、瞬間掛斷實現
瞬間掛斷功能比較復雜。當響鈴時,可以看到的變化如下:(即中間的文字由"正在呼叫..." 變成 "正在響鈴...")
一個想法是抓包分析,找到告訴客戶端對面正在響鈴的包,但是很快放棄了。這么多包,可能還加密了,很難分析。
另一個想法就是,找到SOUI這個第三方UI設置TEXT文本的API,雖然對這個UI庫一點都不懂,但很容易猜到API的名
字應該帶有text。其dll文件為soui.dll,于是在od查找此模塊所有api,找到以下7個候選API:
- 5440161B .text 輸出 SOUI::CSimpleWnd::SetWindowTextW
- 543CDC62 .text 輸出 SOUI::SComboBase::SetWindowTextW
- 543E6759 .text 輸出 SOUI::SRichEdit::SetWindowTextW
- 543FC984 .text 輸出 SOUI::SWindow::SetWindowTextW
-
- 543CB871 .text 輸出 SOUI::SLink::DrawTextW
- 543CB76A .text 輸出 SOUI::SStatic::DrawTextW
- 543FA10F .text 輸出 SOUI::SWindow::DrawTextW
全部設置斷點,然后撥打號碼測試。很快就發現SWindow::SetWindowTextW 斷點下"正在響鈴..."參數。
定位到關鍵API。現在的問題就是怎么告訴我們程序,已經開始響鈴了。 想法一:修改API,如果參數為"正在響鈴...",
就告訴我們程序開始響鈴了。(但是不知道修改DLL怎么保存) 想法二:查看調用這個API的主模塊語句。很幸運地發現,
調用次API的那個語句只用來傳遞"正在響鈴...",也就是不和其他語句混用。所以直接修改這里就行了。 原先的匯編語句為:
(我這邊主模塊基地址為0x008c0000,以下語句地址為0x008d80e4)
- mov edx,dword ptr ds[ebx+0x30
- push eax //字符串"正在響鈴..."
- call edx //調用SWindow::SetWindowText
修改后為:
- 地址008d80e4:(6個字節替換 )
- jmp 0x00af2610
- nop
-
- 地址:00af2610(原先為0填充區域)
- pushad
- mov edx,dword ptr ds:[ebx+0x30
- push eax
- inc [0xaf260c //注意:此處我們設置一個疊加器表示是否已經響鈴了,我們程序再通過ReadProcessMemory定時讀取這個值
- call edx
- popad
- jmp 008d80ea //繼續原來的流程
這樣程序就改好了.注意:上面我們使用0填充區域的4個字節,設置累加器,用于判斷響鈴是否發生(初始值為4,期間API執行兩次變成6,
為什么是不是一次我也不知道,但就是兩次,表示正在響鈴),我們程序讀取這個值(ReadProcessMemory)后,會再將其置4。
四、外部程序
登錄上述修改后的客戶端,執行這個C++程序,傳入電話號碼,就會自動撥號了,響鈴瞬間自動掛斷)
(使用修改后的阿里通客戶端,才可以實現自動掛斷功能。超過1MB好像沒辦法上傳)
- #include<windows.h>
- #include<stdio.h>
-
- #define CNT_ADDR 0x00af260c
- #define BTN_1 0x010d01d1
- #define BTN_2 0x010d0221
- #define BTN_3 0x010d0301
- #define BTN_4 0x014d01d1
- #define BTN_5 0x014d0221
- #define BTN_6 0x014d0301
- #define BTN_7 0x018d01d1
- #define BTN_8 0x018d0267
- #define BTN_9 0x018d0301
- #define BTN_0 0x01bd0267
- #define BTN_BACKSPACE 0x009c02f1
- #define BTN_CALL 0x02320260
- #define BTN_STOP 0x01db02c1
- #define BTN_DIAL_PAGE 0x00AB0024
- static int btn_pos[12]={BTN_0,BTN_1,BTN_2,BTN_3,BTN_4,BTN_5,BTN_6,BTN_7,BTN_8,BTN_9};
- int read_count(HWND hwnd){ //讀取阿里通客戶端,我們設置的累加器。其初值為4。當其為6時(因為SWindow::SetWindowTest會執行兩次,
- 我也不知道為什么兩次),表示正在響鈴
- int ret;
- DWORD pid;
- GetWindowThreadProcessId(hwnd,&pid);
- HANDLE hProcess=OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION |
- PROCESS_VM_READ | PROCESS_VM_WRITE, 0, pid);
- if (hProcess==0){printf("OpenProcess失敗...\n");exit(-1);}
- DWORD bytes_read=0;
- bool bIsOk=ReadProcessMemory(hProcess,(LPCVOID)CNT_ADDR,(LPVOID)&ret,4,&bytes_read);
- if (!bIsOk || bytes_read!=4){
- printf("進程讀取失敗...ok=%d bytes_read=%d\n",bIsOk,bytes_read);
- exit(-1);
- }
- CloseHandle(hProcess);
- //printf("ret=%d\n",ret);
- return ret;
- }
- int reset_count(HWND hwnd){ //將累加器重置為0
- DWORD pid;
- GetWindowThreadProcessId(hwnd,&pid);
- HANDLE hProcess=OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_
- VM_OPERATION | PROCESS_VM_READ |
- PROCESS_VM_WRITE, 0, pid);
- if (hProcess==0){printf("OpenProcess失敗...\n");exit(-1);}
-
- char data[4];data[0]=0x4;data[1]=0x0;data[2]=0;data[3]=0;
- //int *k=(int*)data;
- //printf("k=%x\n",*k);
- DWORD bytes_write;
- bool bIsOk=WriteProcessMemory(hProcess,(LPVOID)CNT_ADDR,data,4,&bytes_write);
- if (!bIsOk || bytes_write!=4){printf("進程寫入失敗...\n");exit(-1);}
- if (read_count(hwnd)!=4){
- printf("unknown error!\n");
- }
- CloseHandle(hProcess);
- return 0;
- }
- int waitForRing(HWND hwnd){ //等待"正在響鈴..."出現
- if (hwnd==0){printf("hwnd=0\n");exit(-1);}
- while (true){
- if (read_count(hwnd)==6){
- //printf("start ringing...!\n");
- reset_count(hwnd);
- break;
- }
- Sleep(100);
- }
- return 0;
- }
- class ALI{
- public:
- HWND hwnd;
- int click(int pos){
- if (hwnd)SendMessage(hwnd,WM_LBUTTONUP,0,pos);
- else exit(-1);
- return 0;
- }
- int clear(){ //清空電話欄
- for (int i=0;i<30;i++) {
- if (click(BTN_BACKSPACE)==-1)return -1;
- }
- return 0;
- }
- int call(char *phone){ //發送消息自動按鍵,并撥號
- hwnd=FindWindow(0,"阿里通");
- //printf("hwnd=%x\n",hwnd);
- click(BTN_DIAL_PAGE);
- //exit(-2);
- clear();
- int len=strlen(phone);
- if (len>11 || len<8)return -1;
- for (int i=0;i<len;i++){
- click(btn_pos[phone[i]-'0']);
- }
- click(BTN_CALL);
- //printf("waitForRing...\n");
- waitForRing(hwnd);
-
- click(BTN_STOP);
- Sleep(5000);
- return 0;
- }
- };
-
- int main(int argc,char** argv){
- ALI ali;
- if (argc<2) return -1;
- ali.call(argv[1]);
- return 0;
- }
-
|