有这么一段代码,连接数超过100后,再次连接就连接不上了,直接返回0

.版本 2

.计次循环首 (150, i)
连接句柄 = 模块类.UConnect (客户句柄, “127.0.0.1”, 2020, 到长整数 (id), 假, 1, “”)
编辑框1.加入文本 (到文本 (i) + “ ” + 取十六进制文本 (连接句柄) + #换行符)
.计次循环尾 ()

关键信息:UConnect 和 0

IDA载入目标文件,查看字符串窗口,看到:

.data:10044074    00000011    C    UConnect called\n

双击字符串来到:

.data:10044074 aUconnectCalled db 'UConnect called',0Ah,0  

然后鼠标右键点击 Xrefs graph to

发现只有函数 FastUdxApi_6 里面引用到字符串 UConnect called'

IDA进入函数FastUdxApi_6 然后F5代码如下:

int __stdcall FastUdxApi_6(int a1, int a2, int a3, int a4, int a5, int a6, __int16 a7, int a8)
{
void *v8; // eax
int v9; // eax
int v10; // esi
int v12; // [esp+8h] [ebp-Ch]
int v13; // [esp+Ch] [ebp-8h]
char v14; // [esp+10h] [ebp-4h]

v8 = sub_10002B30(); // call 1
(*(void (__thiscall **)(void *, char *))(*(_DWORD *)v8 + 12))(v8, aUconnectCalled);// call 2
v12 = 0;
v13 = 0;
v14 = 0;
LOWORD(v12) = a7;
v9 = (*(int (__stdcall **)(int, int, int, int, int, _DWORD, _DWORD, signed int, int, int *, _DWORD, signed int))(*(_DWORD *)a1 + 8))(
a2,
a3,
a6,
a4,
a5,
0,
0,
100,
a8,
&v12,
0,
1); // call 3 sub_10006740
v10 = v9;
if ( a6 && (*(int (__thiscall **)(int))(*(_DWORD *)v9 + 68))(v9) )// call 4
(*(void (__thiscall **)(int))(*(_DWORD *)v10 + 60))(v10);// call 5
return v10;
}

发现里面有5个Call,Call1的代码IDA可以直接看到,进去Call1里面,没发现异常的地方

另外4个Call的地址无法在IDA里面看到,怎么办?

打开 x96dbg,在地址 FastUdxApi_6 下断,断下后,不要急着看汇编代码

直接F8一路走下去,看看5个Call中是哪个Call返回了连接句柄,Call返回值在EAX寄存器中,注意观察

F8单步发现Call3执行后,EAX返回了连接句柄,说明Call3就是我们要找的函数

100011A0 | 83EC 0C                  | sub esp,C                                                                        | UConnect called
100011A3 | 56 | push esi |
100011A4 | 57 | push edi |
100011A5 | E8 86190000 | call tongxin.10002B30 | Call 1
100011AA | 8B10 | mov edx,dword ptr ds:[eax] |
100011AC | 68 74400410 | push tongxin.10044074 | 10044074:"UConnect called\n"
100011B1 | 8BC8 | mov ecx,eax |
100011B3 | FF52 0C | call dword ptr ds:[edx+C] | Call 2
100011B6 | 33C0 | xor eax,eax |
100011B8 | 6A 01 | push 1 |
100011BA | 894424 0C | mov dword ptr ss:[esp+C],eax |
100011BE | 66:8B4C24 34 | mov cx,word ptr ss:[esp+34] |
100011C3 | 894424 10 | mov dword ptr ss:[esp+10],eax |
100011C7 | 8B7C24 30 | mov edi,dword ptr ss:[esp+30] |
100011CB | 884424 14 | mov byte ptr ss:[esp+14],al |
100011CF | 50 | push eax |
100011D0 | 8D4424 10 | lea eax,dword ptr ss:[esp+10] |
100011D4 | 66:894C24 10 | mov word ptr ss:[esp+10],cx |
100011D9 | 50 | push eax |
100011DA | 8B4424 40 | mov eax,dword ptr ss:[esp+40] |
100011DE | 50 | push eax |
100011DF | 8B4424 38 | mov eax,dword ptr ss:[esp+38] |
100011E3 | 8B4C24 28 | mov ecx,dword ptr ss:[esp+28] |
100011E7 | 6A 64 | push 64 |
100011E9 | 6A 00 | push 0 |
100011EB | 6A 00 | push 0 |
100011ED | 8B11 | mov edx,dword ptr ds:[ecx] |
100011EF | 50 | push eax |
100011F0 | 8B4424 44 | mov eax,dword ptr ss:[esp+44] |
100011F4 | 50 | push eax |
100011F5 | 8B4424 44 | mov eax,dword ptr ss:[esp+44] |
100011F9 | 57 | push edi |
100011FA | 50 | push eax |
100011FB | 8B4424 48 | mov eax,dword ptr ss:[esp+48] |
100011FF | 50 | push eax |
10001200 | FF52 08 | call dword ptr ds:[edx+8] | Call 3 获取连接句柄
10001203 | 85FF | test edi,edi |
10001205 | 8BF0 | mov esi,eax |
10001207 | 74 12 | je tongxin.1000121B |
10001209 | 8B16 | mov edx,dword ptr ds:[esi] |
1000120B | 8BCE | mov ecx,esi |
1000120D | FF52 44 | call dword ptr ds:[edx+44] | Call 4
10001210 | 85C0 | test eax,eax |
10001212 | 74 07 | je tongxin.1000121B |
10001214 | 8B06 | mov eax,dword ptr ds:[esi] |
10001216 | 8BCE | mov ecx,esi |
10001218 | FF50 3C | call dword ptr ds:[eax+3C] | Call 5
1000121B | 8BC6 | mov eax,esi |
1000121D | 5F | pop edi |
1000121E | 5E | pop esi |
1000121F | 83C4 0C | add esp,C |
10001222 | C2 2000 | ret 20 |

然后在Call3下个断点,重新载入程序,在Call3断下后,F7跟进去,得到Call 3的地址为 10006740

此时回到IDA,打开sub_10006740 然后F5代码如下:

_DWORD *__thiscall sub_10006740(void *this, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int ArgList, int a11, int a12, int a13)
{
char *v13; // ebx
int *v14; // edi
_DWORD *v15; // ebp
const char *v16; // esi
unsigned int v17; // kr04_4
unsigned int v18; // kr08_4
_DWORD *result; // eax
int v20; // eax
unsigned __int8 v21; // cl
int (__thiscall ***v22)(_DWORD); // eax
int v23; // eax
int v24; // ecx
int v25; // eax
int v26; // esi
int *v27; // eax
int v28; // esi
int v29; // eax
int v30; // eax
bool v31; // zf
unsigned int v32; // kr14_4
unsigned int v33; // kr14_4
int v34; // esi
int v35; // ecx
int v36; // edx
int v37; // edi
int v38; // eax
int v39; // edx
int v40; // eax
char v41; // dl
int v42; // eax
int v43; // edx
int v44; // edx
char v45; // al
char v46; // [esp-10h] [ebp-64h]
int v47; // [esp-Ch] [ebp-60h]
int v48; // [esp-8h] [ebp-5Ch]
signed int v49; // [esp-4h] [ebp-58h]
int v50; // [esp+10h] [ebp-44h]
int v51; // [esp+14h] [ebp-40h]
int v52; // [esp+18h] [ebp-3Ch]
int v53; // [esp+1Ch] [ebp-38h]
char *v54; // [esp+20h] [ebp-34h]
unsigned int v55; // [esp+24h] [ebp-30h]
int v56; // [esp+28h] [ebp-2Ch]
char v57; // [esp+2Ch] [ebp-28h]
int v58; // [esp+48h] [ebp-Ch]
int v59; // [esp+50h] [ebp-4h]
int ArgLista; // [esp+78h] [ebp+24h]

v13 = (char *)this;
memset(&v57, 0, 0x1Cu);
v14 = &v58;
v15 = 0;
v50 = 0;
if ( a11 && *(_WORD *)a11 == -6 )
v50 = 1;
v16 = (const char *)ArgList;
v51 = 0;
if ( !ArgList || (v17 = strlen((const char *)ArgList) + 1, v14 = (int *)(ArgList + v17), v17 == 1) || v50 )
{
if ( a2 )
{
v49 = (unsigned __int16)a3;
v48 = a2;
sub_10002360((int)v13, 0, (int)v14, ArgList, aFastudxNewConn_0, a2, (unsigned __int16)a3);
}
else
{
v49 = (unsigned __int16)a3;
sub_10002360((int)v13, 0, (int)v14, ArgList, aFastudxNewConn_1, (unsigned __int16)a3);
}
}
else
{
v18 = strlen((const char *)ArgList) + 1;
v14 = (int *)(ArgList + v18);
sub_10002360((int)v13, 0, ArgList + v18, ArgList, aFastudxNewConn, ArgList, v18 - 1);
v51 = 1;
result = (_DWORD *)sub_1001F580(&v57, ArgList);
if ( !result )
return result;
}
if ( sub_10009E30((int)v13, (int)v13, 0, (int)v14, 1) )// 注意这个函数,如果返回值是true,则返回0
return 0;
v20 = sub_10018AB0(v13 + 3852);
v21 = v13[4980];
v52 = v20;
v22 = (int (__thiscall ***)(_DWORD))(*(_DWORD *)(*((_DWORD *)v13 + 1243)
+ 4 * ((signed int)v21 % *((_DWORD *)v13 + 1244)))
+ 36);
v13[4980] = v21 + 1;
v23 = (**v22)(v22);
if ( v23 )
v15 = (_DWORD *)(v23 - 8);
v15[7] = v13;
if ( a11 )
{
v24 = (int)(v15 + 593);
v15[593] = *(_DWORD *)a11;
*(_DWORD *)(v24 + 4) = *(_DWORD *)(a11 + 4);
*(_BYTE *)(v24 + 8) = *(_BYTE *)(a11 + 8);
}
if ( a12 )
{
v25 = (*(int (__thiscall **)(int))(*(_DWORD *)a12 + 8))(a12);
v26 = v25;
if ( v25 )
{
if ( v25 == 1 )
{
if ( !(byte_10049228 & 1) )
{
byte_10049228 |= 1u;
sub_10002500(&dword_10049240);
atexit(unknown_libname_1);
}
v27 = (int *)(*(int (__thiscall **)(int *, signed int))dword_10049240)(&dword_10049240, 10240);
goto LABEL_31;
}
if ( !(byte_10049228 & 1) )
{
byte_10049228 |= 1u;
sub_10002500(&dword_10049240);
atexit(unknown_libname_1);
}
v49 = v26;
}
else
{
if ( !(byte_10049228 & 1) )
{
byte_10049228 |= 1u;
sub_10002500(&dword_10049240);
atexit(unknown_libname_1);
}
v49 = 1024;
}
v27 = (int *)(*(int (__thiscall **)(int *, signed int))dword_10049240)(&dword_10049240, v49);
LABEL_31:
v15[596] = v27;
v28 = *v27;
v29 = (*(int (__thiscall **)(int))(*(_DWORD *)a12 + 8))(a12);
v30 = (*(int (__thiscall **)(int, int))(*(_DWORD *)a12 + 4))(a12, v29);
(*(void (__thiscall **)(_DWORD, int))(v28 + 28))(v15[596], v30);
v16 = (const char *)ArgList;
}
sub_10012130(v15);
sub_10012120(v52);
v31 = v50 == 0;
v15[497] = 1000 * *((_DWORD *)v13 + 1248);
if ( v31 && v51 )
{
qmemcpy((void *)v15[474], &v57, 0x1Cu);
v16 = (const char *)ArgList;
v15[489] = sub_1001F290(ArgList);
}
v54 = 0;
LOBYTE(v53) = ArgList;
v55 = 0;
v56 = 0;
std::basic_string<char,std::char_traits<char>,std::allocator<char>>::assign(
&v53,
aMasterUdxSocke,
strlen(aMasterUdxSocke));
v59 = 0;
if ( v50 )
{
if ( v16 )
{
if ( strlen(v16) != 0 )
{
v32 = strlen(v16) + 1;
if ( (unsigned __int8)std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Grow(
&v53,
v32 - 1,
1) )
{
v33 = v32 - 1;
qmemcpy(v54, v16, v33);
v55 = v33;
v54[v33] = 0;
}
}
}
}
ArgLista = 0;
if ( *((_DWORD *)v13 + 1098) > 0 )
{
v34 = 0;
do
{
v35 = *((_DWORD *)v13 + 1097);
v36 = *v15;
v49 = (signed int)v15;
v37 = v35 + v34;
v38 = (*(int (__thiscall **)(_DWORD *))(v36 + 100))(v15) & 7;
if ( v38 < 0 )
v38 = (((_BYTE)v38 - 1) | 0xFFFFFFF8) + 1;
if ( !sub_10003530((char **)(v37 + 60 * v38), v49) )
break;
v34 += 480;
++ArgLista;
}
while ( ArgLista < *((_DWORD *)v13 + 1098) );
}
v39 = *v15;
v49 = (signed int)v15;
v40 = (*(int (__thiscall **)(_DWORD *))(v39 + 100))(v15) & 7;
if ( v40 < 0 )
v40 = (((_BYTE)v40 - 1) | 0xFFFFFFF8) + 1;
sub_10003530((char **)&v13[60 * v40 + 3908], v49);
v15[488] = *((_DWORD *)v13 + 1246);
v41 = v53;
++*((_DWORD *)v13 + 1246);
v46 = v41;
v47 = 0;
v48 = 0;
v49 = 0;
std::basic_string<char,std::char_traits<char>,std::allocator<char>>::assign(
&v46,
&v53,
0,
std::basic_string<char,std::char_traits<char>,std::allocator<char>>::npos);
v42 = sub_1001B200(v13 + 516, v46, v47, v48, v49);
v49 = a3;
v48 = a2;
v15[21] = v42;
sub_100219C0(v48, v49);
v43 = a6 | a5;
if ( __PAIR__(a6, a5) )
{
v44 = *v15;
v49 = a6;
v48 = a5;
(*(void (__thiscall **)(_DWORD *, int, int))(v44 + 112))(v15, a5, a6);
}
if ( __PAIR__(a8, a7) )
*(_DWORD *)((*(int (__thiscall **)(_DWORD *))(*v15 + 96))(v15) + 20) = a7;
*(_DWORD *)((*(int (__fastcall **)(_DWORD *, int))(*v15 + 96))(v15, v43) + 16) = a9;
sub_1000DDF0(v15 + 14);
sub_10024040(v15 + 18);
if ( a4 && !*((_DWORD *)v13 + 97) )
sub_1000DE00(v15[497]);
if ( !a13 )
(*(void (__thiscall **)(_DWORD *))(*v15 + 60))(v15);
(*(void (__thiscall **)(_DWORD *))(v15[2] + 4))(v15 + 2);
if ( v54 )
{
v45 = *(v54 - 1);
if ( v45 && v45 != -1 )
*(v54 - 1) = v45 - 1;
else
sub_100385C0(v54 - 1);
}
return v15;
}

有200多行代码,不用仔细看,粗劣浏览了下,在85行看到了可疑的地方:

  if ( sub_10009E30((int)v13, (int)v13, 0, (int)v14, 1) )// 注意这个函数,如果返回值是true,则返回0
    return 0;

子函数 sub_10009E30 很是可疑,直接双击进去看看:

int __userpurge sub_10009E30@<eax>(int a1@<ecx>, int a2@<ebx>, int a3@<ebp>, int a4@<edi>, int ArgList)
{
void *v5; // esi
int v6; // eax

v5 = (void *)(a1 + 3852);
if ( sub_10018A20((void *)(a1 + 3852)) < 100 )// 终于看到了熟悉的数字 100
return 0;
v6 = sub_10018A20(v5);
sub_10002360(a2, a3, a4, (int)v5, aServerOverflow, ArgList, v6);
return 1;
}

哈哈就是它了,代码不多, sub_10018A20 函数应该就是获取当前连接数的函数了

到这里分析就结束了,怎么修改就不说了。。。