XX通自动拨号、瞬间挂断实现
本帖最后由 ubuntu 于 2019-6-6 18:36 编辑用于整人用的,立刻挂断时阿里通不收费。by cjf@xmu
流程:写程序向客户端发送消息,实现拨号功能;修改客户端,方便我们的程序获知对方正在响铃,然后立刻挂断。
一、文件脱壳
客户端加了个ASPACK 2.12的壳
(1)先清除ASLR标记(ASLR用于随机程序载入基地址,最好先清除掉)
(2)直接使用脱壳机脱壳。
二、自动拨号功能
原理:自动拨号,很自然的思路就是把子窗体控件找出来,然后从外部发送消息过来,实现按钮点击。
(1)原先的思路是使用spy++把子控件都找出来,但是分析发现阿里通使用了第三方UI库(SOUI),SPY++什么都找不到。
(2)那就直接调试——产生按键的消息找出来。
直接拉入OD,直接在API DispatchMessage()中设置消息条件断点,拦截单击释放事件。
拦截条件为:[+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:
push eax
inc //注意:此处我们设置一个叠加器表示是否已经响铃了,我们程序再通过ReadProcessMemory定时读取这个值
calledx
popad
jmp 008d80ea //继续原来的流程
这样程序就改好了.
注意:上面我们使用0填充区域的4个字节,设置累加器,用于判断响铃是否发生(初始值我改为4,一次响铃时,此API执行两次,而变成6,至于为什么是不是一次我也没去分析,但就是两次,表示正在响铃),我们程序定时读取这个值(ReadProcessMemory)后,等到值为6时,则响铃成功,然后再将其置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={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){ //将累加器重置为4(随便设置的一个数字)
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;data=0x4;data=0x0;data=0;data=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-'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);
return 0;
}
下载地址:http://pan.baidu.com/s/1dESFyVn
用法,ali_final.exe替换掉原来客户端。
然后打开cmd,命令call.exe 139xxxxxxxx ,就会自动打了。
注:想要循环的话,把c++ 中main函数ali.call(argv)改成循环的, 重新编译下就好了,一小时一个号码貌似最多打10次,否则被封。被封后,过一段时间又可以用了。
本帖最后由 Valkyrie-Madoka 于 2017-5-12 22:43 编辑
确实可以用,使用方法我说的明确些吧。解压出来的ali_Final.exe重名命名成客户端里的Alicall.exe然后把2个文件都复制进客户端。命令提示符是要根据你的客户端路径来完成的比如我的是D盘正确的使用CMD命令就是E:\Alicall\call.exe 139XXXXXXXX,这样就可以使用了。发现个问题,就是对方秒接电话还是会扣费的...... 本帖最后由 vcvycy 于 2017-5-13 12:48 编辑
Valkyrie-Madoka 发表于 2017-5-12 21:48
确实可以用,使用方法我说的明确些吧。解压出来的ali_Final.exe重名命名成客户端里的Alicall.exe然后把2个 ...
确实会有秒接的情况,因为网络延迟,客户端告诉我们对面响铃的时候,对方可能已经在响铃1~2秒,这个应该是没办法处理的。 格式全乱了,怎么重新编辑= = ........赞一下 支持一下 感觉这样的话就实现了电话骚扰的功能 。。。良心发现!!! 真坏...... 没啥用,呼叫次数多了就封号了。同一个IP登录多了也封号 哈哈哈,这样以后就可以随便拨打骚扰电话了哈!!!这个软件有点{:1_925:} 楼主真强大