linux qq 崩溃调试分析

First Post:

Last Update:

Word Count:
5.7k

Read Time:
29 min

linux qq 崩溃调试分析

QQ调试报告

调试者

I0gan

blog: http://i0gan.cn

github: https://github.com/i0gan

保护

1
2
3
4
5
6
7
8
9
10
┌[logan☮arch]-(/usr/bin)
└> checksec qq
[!] Unknown configuration section 'update'
[*] '/usr/bin/qq'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled

问题

qq在登录之后在拉去消息和好友列表时出现段错误, 在反映比较慢的电脑上出现几率比较小, 在反映过快的电脑中, 每次基本都直接崩溃.

影响版本

2.0.0

原因

多线程条件竞争, 导致对象释放重利用, 然而在调用该函数指针时, 会出现内存地址非法调用

证实: 调试时, 在登录之后, 只运行主线程, 阻断其他线程运行, 能够成功保证登录之后不会崩溃, 只是接受不了消息

其他

由于代码量比较大, 时间性的原因, 只能先暂时提供一下调试信息, 后期会不断更新调试结果, 找出对于的具体漏洞所在

触发段错误漏洞代码块偏移

0xbfdfa0 (vul 1)

0xCCB500 (vul 2)

调试

收到系统信号: sigsegv

线程信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
pwndbg> info threads
Id Target Id Frame
1 Thread 0x7ffff6964940 (LWP 6251) "qq" 0x00007ffff7ce49e5 in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
2 Thread 0x7ffff6963640 (LWP 6258) "qq" 0x00007ffff7e376a2 in pthread_cond_wait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
3 Thread 0x7ffff6162640 (LWP 6259) "ThreadPoolServi" 0x00007ffff70485de in epoll_wait () from /usr/lib/libc.so.6
5 Thread 0x7ffff5160640 (LWP 6261) "Qnox_LogicThrea" 0x00007ffff70485de in epoll_wait () from /usr/lib/libc.so.6
6 Thread 0x7ffff495f640 (LWP 6262) "Qnox_IOThread" 0x00007ffff70485de in epoll_wait () from /usr/lib/libc.so.6
7 Thread 0x7ffff415e640 (LWP 6263) "ThreadPoolForeg" 0x00007ffff7e379c8 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
10 Thread 0x7ffff215a640 (LWP 6267) "inotify_reader" 0x00007ffff703fb7b in select () from /usr/lib/libc.so.6
14 Thread 0x7ffff094f640 (LWP 6270) "qq" 0x00007ffff7e376a2 in pthread_cond_wait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
16 Thread 0x7ffff1158640 (LWP 6290) "ThreadPoolForeg" 0x0000555555ff85a0 in ?? ()
17 Thread 0x7ffff1959640 (LWP 6291) "ThreadPoolForeg" 0x00007ffff7e379c8 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
18 Thread 0x7ffff295b640 (LWP 6292) "ThreadPoolForeg" 0x00007ffff7e379c8 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /usr/lib/libpthread.so.0
19 Thread 0x7ffff315c640 (LWP 6293) "ThreadPoolForeg" 0x0000555556000aa0 in ?? ()
20 Thread 0x7ffff395d640 (LWP 6294) "gmain" 0x00007ffff703d46f in poll () from /usr/lib/libc.so.6
21 Thread 0x7fffee64f640 (LWP 6295) "pool-qq" 0x00007ffff7042d5d in syscall () from /usr/lib/libc.so.6
* 22 Thread 0x7fffede4e640 (LWP 6296) "gdbus" 0x00007ffff7ce49e5 in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0

段错误

主线程段错误信号

1
2
Thread 1 "qq" received signal SIGSEGV, Segmentation fault.
0x00007ffff7ce49e5 in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0

调试如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────
RAX 0x0
RBX 0x7ffff7000000 (____wcstof128_l_internal+1168) ◂— adc eax, 0x748b0000
RCX 0x7ffff7d42938 ◂— 0x6f5347007065656b /* 'keep' */
RDX 0x7ffff7e450a0 (__pthread_keys) ◂— 0x1
RDI 0x134a77fdde60 ◂— 0xffffecb700000002
RSI 0x7ffff7ce498d (g_main_context_dispatch+493) ◂— mov rdi, qword ptr [rsp + 0x18]
R8 0x134a7710b520 ◂— 0x0
R9 0x7fffffffd880 ◂— 0x3000000028 /* '(' */
R10 0x7ffff7fca080
R11 0x286
R12 0x1
R13 0x134a77743890 ◂— 0x0
R14 0x134a77109dc0 ◂— 0x0
R15 0x0
RBP 0x134a774f4bd0 —▸ 0x134a77fdde60 ◂— 0xffffecb700000002
RSP 0x7fffffffd970 —▸ 0x134a77fdde60 ◂— 0xffffecb700000002
RIP 0x7ffff7ce49e5 (g_main_context_dispatch+581) ◂— call qword ptr [rbx + 8]
──────────────────────────────────────────[ DISASM ]──────────────────────────────────────────
► 0x7ffff7ce49e5 <g_main_context_dispatch+581> call qword ptr [rbx + 8]
rdi: 0x134a77fdde60 ◂— 0xffffecb700000002
rsi: 0x7ffff7ce498d (g_main_context_dispatch+493) ◂— mov rdi, qword ptr [rsp + 0x18]
rdx: 0x7ffff7e450a0 (__pthread_keys) ◂— 0x1
rcx: 0x7ffff7d42938 ◂— 0x6f5347007065656b /* 'keep' */

rbx + 8内存

1
2
3
4
5
6
7
pwndbg> x /40gx $rbx + 8
0x7ffff7000008 <____wcstof128_l_internal+1176>: 0x2444c74820245c89 0x0ff6850000000058
0x7ffff7000018 <____wcstof128_l_internal+1192>: 0xef894c00001c968e 0x448d4c58244c8d48
0x7ffff7000028 <____wcstof128_l_internal+1208>: 0xf90ee8ea89485024 0x8b44ff438d48ffff
0x7ffff7000038 <____wcstof128_l_internal+1224>: 0xdcacbd0f4c20245c 0x2444894800001b58
0x7ffff7000048 <____wcstof128_l_internal+1240>: 0xed85453ff5834918 0x8b48000012c4850f
0x7ffff7000058 <____wcstof128_l_internal+1256>: 0x48240c6348582454 0x01fb834850244c89

然而 call qword ptr [rbx + 8]这条指令就相当于: call 0x2444c74820245c89, 这个地址是非法地址,所以出现段错误

正常情况调试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────
RAX 0x0
RBX 0x7ffff7dc33a0 —▸ 0x7ffff7cdf140 ◂— lock add dword ptr [rdi], 1
RCX 0x7ffff7d42938 ◂— 0x6f5347007065656b /* 'keep' */
RDX 0x7ffff7e450a0 (__pthread_keys) ◂— 0x1
RDI 0x1392c57a14a0 ◂— 0xffffec6f00000002
RSI 0x7ffff7ce498d (g_main_context_dispatch+493) ◂— mov rdi, qword ptr [rsp + 0x18]
R8 0x1392c57a1520 ◂— 0x0
R9 0x7fffffffd880 ◂— 0x3000000028 /* '(' */
R10 0x7ffff7fca080
R11 0x286
R12 0x1
R13 0x1392c5ddb900 ◂— 0x0
R14 0x1392c579fdc0 ◂— 0x0
R15 0x0
RBP 0x1392c58e8b60 —▸ 0x1392c57a14a0 ◂— 0xffffec6f00000002
RSP 0x7fffffffd970 —▸ 0x1392c57a14a0 ◂— 0xffffec6f00000002
RIP 0x7ffff7ce49e5 (g_main_context_dispatch+581) ◂— call qword ptr [rbx + 8]
──────────────────────────────────────────[ DISASM ]──────────────────────────────────────────
► 0x7ffff7ce49e5 <g_main_context_dispatch+581> call qword ptr [rbx + 8]

0x7ffff7ce49e8 <g_main_context_dispatch+584> mov rdi, r14
0x7ffff7ce49eb <g_main_context_dispatch+587> call g_mutex_lock <0x7ffff7d32250>

通过以上观察, rbx指向的是0x7ffff7cdf140, 则 rbx + 8内存信息如下

1
2
3
4
pwndbg> x /40gx $rbx + 8
0x7ffff7dc33a8: 0x00007ffff7cdf270 0x00007ffff7cdef50
0x7ffff7dc33b8: 0x0000000000000000 0x00001392c618e070
0x7ffff7dc33c8: 0x00007ffff7ce0650 0x0000000000000000

指向的内存如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
pwndbg> x /40gx 0x00007ffff7cdf270
0x7ffff7cdf270: 0x66c30a74012f83f0 0x0000000000841f0f
0x7ffff7cdf280: 0xfd894818478b4855 0x7f8b480674c08548
0x7ffff7cdf290: 0xe95def8948d0ff10 0x001f0f90ffffffc4
0x7ffff7cdf2a0: 0x2e6690ffffffbbe9 0x0000000000841f0f
0x7ffff7cdf2b0: 0x15fffb8953555441 0x48fb6348000e361c
0x7ffff7cdf2c0: 0x8b44000e485a158d 0x000001b8c5894820
0x7ffff7cdf2d0: 0x0587ba0c87c18900 0x25058b48000e4948
0x7ffff7cdf2e0: 0x0080b88b48000e48 0x4400047fb1e80000
0x7ffff7cdf2f0: 0xc35c415d5b006589 0x0000000000841f0f
0x7ffff7cdf300 <g_clear_handle_id>: 0x1074c08545078b44 0x89440000000007c7
0x7ffff7cdf310 <g_clear_handle_id+16>: 0x0000441f0fe6ffc7 0x00000000801f0fc3
0x7ffff7cdf320 <g_get_real_time>: 0x4864f63128ec8348 0x480000002825048b
0x7ffff7cdf330 <g_get_real_time+16>: 0x8948c03118244489 0x48000e37e115ffe7
0x7ffff7cdf340 <g_get_real_time+32>: 0x48000f4240240469 0x24548b4808244403
0x7ffff7cdf350 <g_get_real_time+48>: 0x002825142b486418 0x28c4834805750000
0x7ffff7cdf360 <g_get_real_time+64>: 0x66000e372915ffc3 0x0000000000841f0f
0x7ffff7cdf370 <g_main_context_query>: 0x495641d789495741 0x41fd89495541ce89
0x7ffff7cdf380 <g_main_context_query+16>: 0xf38953c589445554 0x2ebee86708ec8348
0x7ffff7cdf390 <g_main_context_query+32>: 0x854860458b490005 0x31000000c1840fc0
0x7ffff7cdf3a0 <g_main_context_query+48>: 0x2e6634ebe43145f6 0x0000000000841f0f

单步执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
RAX  0x0
RBX 0x7ffff7dc33a0 —▸ 0x7ffff7cdf140 ◂— lock add dword ptr [rdi], 1
RCX 0x7ffff7d42930 ◂— 0x796f7274736564 /* 'destroy' */
RDX 0x7ffff7e450a0 (__pthread_keys) ◂— 0x1
RDI 0x99bbfa157a0 ◂— 0xfffff66600000002
RSI 0x7ffff7ce498d (g_main_context_dispatch+493) ◂— mov rdi, qword ptr [rsp + 0x18]
R8 0x99bbf7f2380 ◂— 0x0
R9 0x7fffede4d9e0 ◂— 0x3000000028 /* '(' */
R10 0x7ffff7fca080
R11 0x286
R12 0x0
R13 0x99bbf9eb250 ◂— 0x0
R14 0x99bbf9f9e70 ◂— 0x0
R15 0x1
RBP 0x99bbf9fc4e0 —▸ 0x99bbfa157a0 ◂— 0xfffff66600000002
RSP 0x7fffede4dac8 —▸ 0x7ffff7ce49e8 (g_main_context_dispatch+584) ◂— mov rdi, r14
RIP 0x7ffff7cdf270 ◂— lock sub dword ptr [rdi], 1

► 0x7ffff7cdf270 lock sub dword ptr [rdi], 1

0x7ffff7cdf276 ret

0x7ffff7ce49e8 <g_main_context_dispatch+584> mov rdi, r14
0x7ffff7ce49eb <g_main_context_dispatch+587> call g_mutex_lock <0x7ffff7d32250>

可以看到, 原来rbx + 8处的内存储存的是一个该处指令的地址, 这里采用lock sub指令进行对线程使用数 - 1, rdi 指向的是被锁的线程.目前为2

lock前缀指令详解

1
2
3
4
LOCK指令前缀会设置处理器的LOCK#信号(译注:这个信号会使总线锁定,阻止其他处理器接管总线访问内存),直到使用LOCK前缀的指令执行结束,这会使这条指令的执行变为原子操作。在多处理器环境下,设置LOCK#信号能保证某个处理器对共享内存的独占使用。
LOCK指令前缀只能用于以下指令,并且要求指令目的操作数为内存操作数,如果源操作数为内存操作数,就会产生undefined opcode异常:ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B,CMPXCHG16B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, XCHG。LOCK指令前缀用于其他任何指令时,也会产生如果源操作数为内存操作数,就会产生undefined opcode异常。另外,XCHG指令默认会设置LOCK#信号,无论是否使用LOCK指令前缀。
LOCK指令前缀经常用于BTS指令,用来在共享内存进行一次read-modify-write操作。
从P6处理器家族开始,如果使用了LOCK指令前缀的指令要访问的目的地址的内容已经缓存在了cache中,那么LOCK#信号一般就不会被设置,但是当前处理器的cache会被锁定,然后缓存一致性(cache coherency )机制会自动确保操作的原子性。

从g_main_context_dispatch结束的可疑地址1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────
RAX 0x1
RBX 0x1665cdb9ed01 ◂— 0x0
RCX 0x7fffffffdac0 —▸ 0x1665cdb9edc8 —▸ 0x5555570bdcb0 —▸ 0x55555617bf10 ◂— push rbp
RDX 0x7ffff7da0251 ◂— 'non-blocking'
RDI 0x1665cda0ddc0 ◂— 0x0
RSI 0x1
R8 0x1665cda0f520 ◂— 0x0
R9 0x7fffffffd920 ◂— 0x3000000028 /* '(' */
R10 0x7ffff7fca080
R11 0x286
R12 0x7fffffffdce8 ◂— '2.0.0-b2'
R13 0x7fffffffdc80 —▸ 0x1665cdb9edd0 —▸ 0x5555570bdd00 —▸ 0x55555617bf20 ◂— push rbp
R14 0x0
R15 0x1665cdb8d2d0 —▸ 0x5555570bc718 —▸ 0x555556151e10 ◂— push rbp
RBP 0x7fffffffdb00 —▸ 0x7fffffffdb30 —▸ 0x7fffffffdbc0 —▸ 0x7fffffffdf10 —▸ 0x55555709abe0 ◂— ...
RSP 0x7fffffffdac0 —▸ 0x1665cdb9edc8 —▸ 0x5555570bdcb0 —▸ 0x55555617bf10 ◂— push rbp
RIP 0x55555615201a ◂— jne 0x555556152063
──────────────────────────────────────────[ DISASM ]──────────────────────────────────────────
0x7ffff7ce3144 <g_main_context_iteration+68> pop rbp
0x7ffff7ce3145 <g_main_context_iteration+69> pop r12
0x7ffff7ce3147 <g_main_context_iteration+71> ret

0x555556152012 mov rcx, qword ptr [r15 + 8]
0x555556152016 cmp byte ptr [rcx + 8], 0
► 0x55555615201a jne 0x555556152063

0x55555615201e setne bl
0x555556152021 mov rdi, qword ptr [rcx]
0x555556152024 mov rax, qword ptr [rdi]
0x555556152027 call qword ptr [rax + 0x20]

0x55555615202a mov rcx, qword ptr [r15 + 8]

程序vmmap

1
2
3
4
5
6
7
0x555555554000     0x555555b69000 r--p   615000 0      /opt/tencent-qq/qq
0x555555b69000 0x5555570a6000 r-xp 153d000 614000 /opt/tencent-qq/qq
0x5555570a6000 0x55555710d000 r--p 67000 1b50000 /opt/tencent-qq/qq
0x55555710d000 0x555557119000 rw-p c000 1bb6000 /opt/tencent-qq/qq
0x555557119000 0x55555717a000 rw-p 61000 0 [heap]
....

程序基址为: 0x555555554000

1
2
pwndbg> p /x 0x555556152012 - 0x555555554000
$4 = 0xbfe012

可疑问题偏移地址:

0xbfe012

找到该调处用汇编代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
0x00bfdfa0      push rbp
0x00bfdfa1 mov rbp, rsp
0x00bfdfa4 push r15
0x00bfdfa6 push r14
0x00bfdfa8 push rbx
0x00bfdfa9 sub rsp, 0x28
0x00bfdfad mov r15, rdi
0x00bfdfb0 movaps xmm0, xmmword [0x00122f40]
0x00bfdfb7 movaps xmmword [rbp - 0x40], xmm0
0x00bfdfbb xorps xmm0, xmm0
0x00bfdfbe movaps xmmword [rbp - 0x30], xmm0
0x00bfdfc2 mov qword [rbp - 0x40], rsi
0x00bfdfc6 mov byte [rbp - 0x38], 0
0x00bfdfca mov r14, qword [rdi + 8]
0x00bfdfce test r14, r14
0x00bfdfd1 je 0xbfdfdc
0x00bfdfd3 mov eax, dword [r14 + 0xc]
0x00bfdfd7 add eax, 1
0x00bfdfda jmp 0xbfdfe1
0x00bfdfdc mov eax, 1
0x00bfdfe1 mov dword [rbp - 0x34], eax
0x00bfdfe4 lea rax, [rbp - 0x40]
0x00bfdfe8 mov qword [r15 + 8], rax
0x00bfdfec mov rdi, qword [r15 + 0x10]
0x00bfdff0 xor esi, esi
0x00bfdff2 jmp 0xbfe00d
0x00bfdff4 nop word cs:[rax + rax]
0x00bfdffe nop
0x00bfe000 test dl, dl
0x00bfe002 jne 0xbfe063
0x00bfe004 xor al, 1
0x00bfe006 mov rdi, qword [r15 + 0x10]
0x00bfe00a movzx esi, al
0x00bfe00d call g_main_context_iteration ; sym.imp.g_main_context_iteration ; 调用
0x00bfe012 mov rcx, qword [r15 + 8]
0x00bfe016 cmp byte [rcx + 8], 0
0x00bfe01a jne 0xbfe063
0x00bfe01c test eax, eax
0x00bfe01e setne bl
0x00bfe021 mov rdi, qword [rcx]
0x00bfe024 mov rax, qword [rdi]
0x00bfe027 call qword [rax + 0x20]
0x00bfe02a mov rcx, qword [r15 + 8]
0x00bfe02e mov qword [rcx + 0x10], rax
0x00bfe032 mov qword [rcx + 0x18], rdx
0x00bfe036 mov rcx, qword [r15 + 8]
0x00bfe03a cmp qword [rcx + 0x10], 0
0x00bfe03f sete al
0x00bfe042 or al, bl
0x00bfe044 movzx edx, byte [rcx + 8]
0x00bfe048 test dl, dl
0x00bfe04a jne 0xbfe000
0x00bfe04c test al, al
0x00bfe04e jne 0xbfe000
0x00bfe050 mov rdi, qword [rcx]
0x00bfe053 mov rax, qword [rdi]
0x00bfe056 call qword [rax + 0x38]
0x00bfe059 mov rcx, qword [r15 + 8]
0x00bfe05d cmp byte [rcx + 8], 0
0x00bfe061 je 0xbfe004
0x00bfe063 mov qword [r15 + 8], r14
0x00bfe067 add rsp, 0x28
0x00bfe06b pop rbx
0x00bfe06c pop r14
0x00bfe06e pop r15
0x00bfe070 pop rbp
0x00bfe071 ret
0x00bfe072 int3
0x00bfe073 int3

IDA伪c代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
char __fastcall sub_BFDFA0(__int64 a1, __int64 a2) //**************  段错误触发函数
{
__int64 v2; // r15
__int64 v3; // r14
int v4; // eax
__int64 v5; // rdi
__int64 i; // rsi
__int64 v7; // rax
__int64 v8; // rdx
_BYTE *v9; // rcx
bool v10; // bl
__int64 v11; // rcx
__int64 v12; // rdx
_QWORD *v13; // rcx
__int64 v14; // rdx
__int128 v16; // [rsp+0h] [rbp-40h]
__int128 v17; // [rsp+10h] [rbp-30h]

v2 = a1;
v16 = xmmword_122F40;
v17 = 0LL;
*(_QWORD *)&v16 = a2;
BYTE8(v16) = 0;
v3 = *(_QWORD *)(a1 + 8);
if ( v3 )
v4 = *(_DWORD *)(v3 + 12) + 1;
else
v4 = 1;
HIDWORD(v16) = v4;
*(_QWORD *)(a1 + 8) = &v16;
v5 = *(_QWORD *)(a1 + 16);
for ( i = 0LL; ; i = (unsigned __int8)(v7 ^ 1) )
{
LODWORD(v7) = g_main_context_iteration(v5, i); //************** 段错误触发函数
v9 = *(_BYTE **)(v2 + 8);
if ( v9[8] )
break;
v10 = (_DWORD)v7 != 0;
v7 = (*(__int64 (__cdecl **)(_QWORD, __int64, __int64, _BYTE *))(**(_QWORD **)v9 + 32LL))(*(_QWORD *)v9, i, v8, v9);
v11 = *(_QWORD *)(v2 + 8);
*(_QWORD *)(v11 + 16) = v7;
*(_QWORD *)(v11 + 24) = v12;
v13 = *(_QWORD **)(v2 + 8);
LOBYTE(v7) = v10 || v13[2] == 0LL;
v14 = *((unsigned __int8 *)v13 + 8);
if ( (_BYTE)v14 || (_BYTE)v7 )
{
if ( (_BYTE)v14 )
break;
}
else
{
LOBYTE(v7) = (*(__int64 (__cdecl **)(_QWORD, __int64, __int64, _QWORD *))(*(_QWORD *)*v13 + 56LL))(
*v13,
i,
v14,
v13);
if ( *(_BYTE *)(*(_QWORD *)(v2 + 8) + 8LL) )
break;
}
v5 = *(_QWORD *)(v2 + 16);
}
*(_QWORD *)(v2 + 8) = v3;
return v7;
}

发现在该函数中,没有加入线程锁, 多线程时条件竞争时导致出现内存错误.

最初漏洞所在:

在<g_main_context_dispatch+581> call qword ptr [rbx + 8]的地方出现内存错误.

该g_main_context_dispatch函数为g_main_context_iteration所调用

1
2
3
4
5
6
7
8
9
10
11
12
13
│  >0x7ffff7ce49b9 <g_main_context_dispatch+537>    lea    r8,[rip+0xbb8c5]
│ 0x7ffff7ce49c0 <g_main_context_dispatch+544> lea rdx,[rip+0x546aa]
│ 0x7ffff7ce49c7 <g_main_context_dispatch+551> call 0x7ffff7d34ad0
│ 0x7ffff7ce49cc <g_main_context_dispatch+556> mov rax,QWORD PTR [rsp+0x18]
│ 0x7ffff7ce49d1 <g_main_context_dispatch+561> sub DWORD PTR [r13+0x0],0x1
│ 0x7ffff7ce49d6 <g_main_context_dispatch+566> mov QWORD PTR [r13+0x8],rax
│ 0x7ffff7ce49da <g_main_context_dispatch+570> pop rcx
│ 0x7ffff7ce49db <g_main_context_dispatch+571> pop rsi
│ 0x7ffff7ce49dc <g_main_context_dispatch+572> test rbx,rbx
│ 0x7ffff7ce49df <g_main_context_dispatch+575> je 0x7ffff7ce49e8 <g_main_context_dispatch+584>
│ 0x7ffff7ce49e1 <g_main_context_dispatch+577> mov rdi,QWORD PTR [rsp]
│ 0x7ffff7ce49e5 <g_main_context_dispatch+581> call QWORD PTR [rbx+0x8] //vul
│ 0x7ffff7ce49e8 <g_main_context_dispatch+584> mov rdi,r14
1
2
3
4
5
► 0x55555615200d    call   g_main_context_iteration@plt <0x5555570a28c0>
rdi: 0x3acdd361fdc0 ◂— 0x0
rsi: 0x0
rdx: 0x7fffffffffffffff
rcx: 0x5555570bdd00 —▸ 0x55555617bf20 ◂— push rbp

调试漏洞函数最后一次状态

崩溃前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 RAX  0x0
RBX 0x317f3a79dc01 ◂— 0x0
RCX 0x7fffffffdac0 —▸ 0x317f3a79dc68 —▸ 0x5555570bdcb0 —▸ 0x55555617bf10 ◂— push rbp
RDX 0x0
RDI 0x317f3a648dc0 ◂— 0x0
RSI 0x0
R8 0x317f3a5c8003 ◂— 0x0
R9 0x0
R10 0x7ffff7fca080
R11 0x286
R12 0x7fffffffdce8 ◂— '2.0.0-b2'
R13 0x7fffffffdc80 —▸ 0x317f3a79dc70 —▸ 0x5555570bdd00 —▸ 0x55555617bf20 ◂— push rbp
R14 0x0
R15 0x317f3a7b8090 —▸ 0x5555570bc718 —▸ 0x555556151e10 ◂— push rbp
RBP 0x7fffffffdb00 —▸ 0x7fffffffdb30 —▸ 0x7fffffffdbc0 —▸ 0x7fffffffdf10 —▸ 0x55555709abe0 ◂— ...
RSP 0x7fffffffdab8 —▸ 0x555556152012 ◂— mov rcx, qword ptr [r15 + 8]
RIP 0x7ffff7ce3100 (g_main_context_iteration) ◂— push r12
─────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────
► 0x7ffff7ce3100 <g_main_context_iteration> push r12

最后一次崩溃g_main_context_iteration的传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 RAX  0x0
RBX 0x317f3a79dc01 ◂— 0x0
RCX 0x7fffffffdac0 —▸ 0x317f3a79dc68 —▸ 0x5555570bdcb0 —▸ 0x55555617bf10 ◂— push rbp
RDX 0x0
RDI 0x317f3a648dc0 ◂— 0x0
RSI 0x0
R8 0x317f3a5c8003 ◂— 0x0
R9 0x0 ; diff
R10 0x17 ; diff
R11 0x10 ; diff
R12 0x7fffffffdce8 ◂— '2.0.0-b2'
R13 0x7fffffffdc80 —▸ 0x317f3a79dc70 —▸ 0x5555570bdd00 —▸ 0x55555617bf20 ◂— push rbp
R14 0x0
R15 0x317f3a7b8090 —▸ 0x5555570bc718 —▸ 0x555556151e10 ◂— push rbp
RBP 0x7fffffffdb00 —▸ 0x7fffffffdb30 —▸ 0x7fffffffdbc0 —▸ 0x7fffffffdf10 —▸ 0x55555709abe0 ◂— ...
RSP 0x7fffffffdab8 —▸ 0x555556152012 ◂— mov rcx, qword ptr [r15 + 8]
RIP 0x7ffff7ce3100 (g_main_context_iteration) ◂— push r12
─────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────
► 0x7ffff7ce3100 <g_main_context_iteration> push r12

0x7ffff7ce3105 <g_main_context_iteration+5> push rbp
0x7ffff7ce3106 <g_main_context_iteration+6> mov rbp, rdi
0x7ffff7ce3109 <g_main_context_iteration+9> sub rsp, 8
0x7ffff7ce310d <g_main_context_iteration+13> test rdi, rdi

g_main_context_dispatch函数最后一次崩溃传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
Continuing.

Thread 1 "qq" hit Breakpoint 2, 0x00007ffff7ce47a0 in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
ERROR: Could not find ELF base!
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
──────────────────────────────────────[ REGISTERS ]──────────────────────────────────────
RAX 0x1
RBX 0x1
RCX 0xf0950bcdd20 ◂— 0x0
RDX 0x1
RDI 0xf094fee6dc0 ◂— 0x0
RSI 0x1
R8 0x0
R9 0x7fffffffd840 ◂— 0x3000000028 /* '(' */
R10 0x7ffff7fca080
R11 0x293
R12 0x3
R13 0xf094fee6dc0 ◂— 0x0
R14 0x7fffffffda10 ◂— 0x352
R15 0x2
RBP 0xf095048bf20 ◂— 0x100000021 /* '!' */
RSP 0x7fffffffd9d8 —▸ 0x7ffff7d38621 ◂— jmp 0x7ffff7d384c0
RIP 0x7ffff7ce47a0 (g_main_context_dispatch) ◂— push r15
───────────────────────────────────────[ DISASM ]────────────────────────────────────────
► 0x7ffff7ce47a0 <g_main_context_dispatch> push r15

0x7ffff7ce47a4 <g_main_context_dispatch+4> mov r14, rdi
0x7ffff7ce47a7 <g_main_context_dispatch+7> push r13
0x7ffff7ce47a9 <g_main_context_dispatch+9> push r12
0x7ffff7ce47ab <g_main_context_dispatch+11> push rbp
0x7ffff7ce47ac <g_main_context_dispatch+12> push rbx
0x7ffff7ce47ad <g_main_context_dispatch+13> sub rsp, 0x68
0x7ffff7ce47b1 <g_main_context_dispatch+17> mov rax, qword ptr fs:[0x28]
0x7ffff7ce47ba <g_main_context_dispatch+26> mov qword ptr [rsp + 0x58], rax
0x7ffff7ce47bf <g_main_context_dispatch+31> xor eax, eax
0x7ffff7ce47c1 <g_main_context_dispatch+33> call g_mutex_lock <0x7ffff7d32250>
────────────────────────────────────────[ STACK ]────────────────────────────────────────
00:0000│ rsp 0x7fffffffd9d8 —▸ 0x7ffff7d38621 ◂— jmp 0x7ffff7d384c0
01:0008│ 0x7fffffffd9e0 ◂— 0x352
02:0010│ 0x7fffffffd9e8 ◂— 0x249b1fe8
03:0018│ 0x7fffffffd9f0 ◂— 0x100000000
04:0020│ 0x7fffffffd9f8 —▸ 0x7ffff7cead90 (g_poll) ◂— mov esi, esi
05:0028│ 0x7fffffffda00 ◂— 0xaaaaaaaaaaaaaaaa
06:0030│ 0x7fffffffda08 ◂— 0x0
07:0038│ r14 0x7fffffffda10 ◂— 0x352
──────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────
► f 0 7ffff7ce47a0 g_main_context_dispatch
f 1 7ffff7d38621
f 2 7ffff7ce3131 g_main_context_iteration+49
f 3 555556152012
f 4 55555617d0e5
f 5 5555561660ee
f 6 555555f0f6f4
f 7 7ffff6f70152 __libc_start_main+242
─────────────────────────────────────────────────────────────────────────────────────────
pwndbg>
Continuing.

Thread 1 "qq" hit Breakpoint 2, 0x00007ffff7ce47a0 in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
ERROR: Could not find ELF base!
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
──────────────────────────────────────[ REGISTERS ]──────────────────────────────────────
RAX 0x1
RBX 0x1
RCX 0x4 ;diff
RDX 0x1
RDI 0xf094fee6dc0 ◂— 0x0
RSI 0x1
R8 0x0
R9 0x7fffffffd840 ◂— 0x3000000028 /* '(' */
R10 0x7ffff7fca080
R11 0x293
R12 0x3
R13 0xf094fee6dc0 ◂— 0x0
R14 0x7fffffffda10 ◂— 0x353 ; diff ++
R15 0x2
RBP 0xf095048bf20 ◂— 0x100000021 /* '!' */
RSP 0x7fffffffd9d8 —▸ 0x7ffff7d38621 ◂— jmp 0x7ffff7d384c0
RIP 0x7ffff7ce47a0 (g_main_context_dispatch) ◂— push r15
───────────────────────────────────────[ DISASM ]────────────────────────────────────────
► 0x7ffff7ce47a0 <g_main_context_dispatch> push r15

0x7ffff7ce47a4 <g_main_context_dispatch+4> mov r14, rdi
0x7ffff7ce47a7 <g_main_context_dispatch+7> push r13
0x7ffff7ce47a9 <g_main_context_dispatch+9> push r12
0x7ffff7ce47ab <g_main_context_dispatch+11> push rbp
0x7ffff7ce47ac <g_main_context_dispatch+12> push rbx
0x7ffff7ce47ad <g_main_context_dispatch+13> sub rsp, 0x68
0x7ffff7ce47b1 <g_main_context_dispatch+17> mov rax, qword ptr fs:[0x28]
0x7ffff7ce47ba <g_main_context_dispatch+26> mov qword ptr [rsp + 0x58], rax
0x7ffff7ce47bf <g_main_context_dispatch+31> xor eax, eax
0x7ffff7ce47c1 <g_main_context_dispatch+33> call g_mutex_lock <0x7ffff7d32250>
────────────────────────────────────────[ STACK ]────────────────────────────────────────
00:0000│ rsp 0x7fffffffd9d8 —▸ 0x7ffff7d38621 ◂— jmp 0x7ffff7d384c0
01:0008│ 0x7fffffffd9e0 ◂— 0x353
02:0010│ 0x7fffffffd9e8 ◂— 0x15108cf6
03:0018│ 0x7fffffffd9f0 ◂— 0x100000000
04:0020│ 0x7fffffffd9f8 —▸ 0x7ffff7cead90 (g_poll) ◂— mov esi, esi
05:0028│ 0x7fffffffda00 ◂— 0xaaaaaaaaaaaaaaaa
06:0030│ 0x7fffffffda08 ◂— 0x0
07:0038│ r14 0x7fffffffda10 ◂— 0x353
──────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────
► f 0 7ffff7ce47a0 g_main_context_dispatch
f 1 7ffff7d38621
f 2 7ffff7ce3131 g_main_context_iteration+49
f 3 555556152012
f 4 55555617d0e5
f 5 5555561660ee
f 6 555555f0f6f4
f 7 7ffff6f70152 __libc_start_main+242
─────────────────────────────────────────────────────────────────────────────────────────
pwndbg>
Continuing.

Thread 1 "qq" received signal SIGSEGV, Segmentation fault.
0x00007ffff7ce49e5 in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
ERROR: Could not find ELF base!
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
──────────────────────────────────────[ REGISTERS ]──────────────────────────────────────
RAX 0x0
RBX 0x7ffff7000000 (____wcstof128_l_internal+1168) ◂— adc eax, 0x748b0000
RCX 0x7ffff7d42938 ◂— 0x6f5347007065656b /* 'keep' */
RDX 0x7ffff7e450a0 (__pthread_keys) ◂— 0x1
RDI 0xf09506b6740 ◂— 0xfffff0f400000002
RSI 0x7ffff7ce498d (g_main_context_dispatch+493) ◂— mov rdi, qword ptr [rsp + 0x18]
R8 0xf094fee8520 ◂— 0x0
R9 0x7fffffffd850 ◂— 0x3000000028 /* '(' */
R10 0x7ffff7fca080
R11 0x286
R12 0x1
R13 0xf0950489980 ◂— 0x0
R14 0xf094fee6dc0 ◂— 0x0
R15 0x2
RBP 0xf0950b47d20 —▸ 0xf09506b6740 ◂— 0xfffff0f400000002
RSP 0x7fffffffd940 —▸ 0xf09506b6740 ◂— 0xfffff0f400000002
RIP 0x7ffff7ce49e5 (g_main_context_dispatch+581) ◂— call qword ptr [rbx + 8]
───────────────────────────────────────[ DISASM ]────────────────────────────────────────
► 0x7ffff7ce49e5 <g_main_context_dispatch+581> call qword ptr [rbx + 8]
rdi: 0xf09506b6740 ◂— 0xfffff0f400000002
rsi: 0x7ffff7ce498d (g_main_context_dispatch+493) ◂— mov rdi, qword ptr [rsp + 0x18]
rdx: 0x7ffff7e450a0 (__pthread_keys) ◂— 0x1
rcx: 0x7ffff7d42938 ◂— 0x6f5347007065656b /* 'keep' */

0x7ffff7ce49e8 <g_main_context_dispatch+584> mov rdi, r14
0x7ffff7ce49eb <g_main_context_dispatch+587> call g_mutex_lock <0x7ffff7d32250>

0x7ffff7ce49f1 <g_main_context_dispatch+593> mov edx, dword ptr [rsp + 0x2c]
0x7ffff7ce49f5 <g_main_context_dispatch+597> mov eax, dword ptr [rbp + 0x2c]
0x7ffff7ce49f8 <g_main_context_dispatch+600> test edx, edx
0x7ffff7ce49fa <g_main_context_dispatch+602> jne g_main_context_dispatch+610 <0x7ffff7ce4a02>

0x7ffff7ce49fc <g_main_context_dispatch+604> and eax, 0xfffffffd
0x7ffff7ce49ff <g_main_context_dispatch+607> mov dword ptr [rbp + 0x2c], eax
0x7ffff7ce4a02 <g_main_context_dispatch+610> and eax, 0x41
0x7ffff7ce4a05 <g_main_context_dispatch+613> cmp eax, 0x41
────────────────────────────────────────[ STACK ]────────────────────────────────────────
00:0000│ rsp 0x7fffffffd940 —▸ 0xf09506b6740 ◂— 0xfffff0f400000002
01:0008│ 0x7fffffffd948 ◂— 0x0
02:0010│ 0x7fffffffd950 —▸ 0x7ffff7d42938 ◂— 0x6f5347007065656b /* 'keep' */
03:0018│ 0x7fffffffd958 ◂— 0xc646f4bc63
04:0020│ 0x7fffffffd960 —▸ 0x7ffff7d42760 ◂— '(unnamed)'
05:0028│ 0x7fffffffd968 ◂— 0x1
06:0030│ 0x7fffffffd970 ◂— 0x0
07:0038│ 0x7fffffffd978 —▸ 0x555555c44670 ◂— push rbp
──────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────
► f 0 7ffff7ce49e5 g_main_context_dispatch+581
f 1 7ffff7d38621
f 2 7ffff7ce3131 g_main_context_iteration+49
f 3 555556152012
f 4 55555617d0e5
f 5 5555561660ee
f 6 555555f0f6f4
f 7 7ffff6f70152 __libc_start_main+242
─────────────────────────────────────────────────────────────────────────────────────────

0x527A0 + 581 == x529e5

其他线程漏洞

经过多线程调试, 找到bug2, 发生在Qnox_LogicThrea线程中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
pwndbg> 

Thread 5 "Qnox_LogicThrea" received signal SIGSEGV, Segmentation fault.
0x000055555621f539 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────[ REGISTERS ]────────────────────────────────────────────────
RAX 0xffffc39f73c44bb8
RBX 0x3c62263bf000 ◂— 0x0
RCX 0x55555621f500 ◂— push rbp
RDX 0xf0
RDI 0x7ffff515f830 ◂— 0xaaaaaaaaaaaaaaaa
RSI 0x3c622690f240 ◂— 0xffffc39f73c44bb8
R8 0x3c62264ca003 ◂— 0x0
R9 0x1
R10 0x7ffff7fca080
R11 0x286
R12 0x0
R13 0xaaaaaaaaaaaaaaaa
R14 0x0
R15 0x3c62267d3000 —▸ 0x5555570c4350 —▸ 0x55555621d7d0 ◂— push rbp
RBP 0x7ffff515f870 —▸ 0x7ffff515f930 —▸ 0x7ffff515fa10 —▸ 0x7ffff515fa60 —▸ 0x7ffff515fac0 ◂— ...
RSP 0x7ffff515f6e0 ◂— 0x0
RIP 0x55555621f539 ◂— call qword ptr [rax + 0x30]
─────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────
► 0x55555621f539 call qword ptr [rax + 0x30]

0x55555621f53c mov edi, 2
0x55555621f541 call 0x55555614f1b0

0x55555621f546 test al, al
0x55555621f548 je 0x55555621f5de

0x55555621f54e lea rsi, [rip - 0xb59197]
0x55555621f555 lea rdi, [rbp - 0x178]
0x55555621f55c mov edx, 0x107
0x55555621f561 mov ecx, 2
0x55555621f566 call 0x55555614f2a0

0x55555621f56b lea rdi, [rbp - 0x170]

可以看到, call qword ptr [rax + 0x30]指令中, rax对应的值为: 0xffffc39f73c44bb8

指令: 0x55555 621f539 - 0x55555 5554000 == 0xccb539

vmmap

1
2
3
4
5
6
0x555555554000     0x555555b69000 r--p   615000 0      /opt/tencent-qq/qq
0x555555b69000 0x5555570a6000 r-xp 153d000 614000 /opt/tencent-qq/qq
0x5555570a6000 0x55555710d000 r--p 67000 1b50000 /opt/tencent-qq/qq
0x55555710d000 0x555557119000 rw-p c000 1bb6000 /opt/tencent-qq/qq
0x555557119000 0x55555717a000 rw-p 61000 0 [heap]

在0xccb539处找到call qword ptr [rax+30h]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
0000000CCB500 ; __unwind {
.text:0000000000CCB500 push rbp
.text:0000000000CCB501 mov rbp, rsp
.text:0000000000CCB504 push r15
.text:0000000000CCB506 push r14
.text:0000000000CCB508 push rbx
.text:0000000000CCB509 sub rsp, 178h
.text:0000000000CCB510 mov r15, rdi
.text:0000000000CCB513 mov rax, fs:28h
.text:0000000000CCB51C mov [rbp+var_20], rax
.text:0000000000CCB520 movaps xmm0, cs:xmmword_122F40
.text:0000000000CCB527 movaps [rbp+var_40], xmm0
.text:0000000000CCB52B mov [rbp+var_30], 0AAAAAAAAh
.text:0000000000CCB532 mov rax, [rsi]
.text:0000000000CCB535 lea rdi, [rbp+var_40]
.text:0000000000CCB539 call qword ptr [rax+30h] // vul
.text:0000000000CCB53C mov edi, 2
.text:0000000000CCB541 call sub_BFB1B0
.text:0000000000CCB546 test al, al
.text:0000000000CCB548 jz loc_CCB5DE
.text:0000000000CCB54E lea rsi, aQnoxMsfMsfping ; "../../qnox/msf/msfping.cc"
.text:0000000000CCB555 lea rdi, [rbp+var_178]
.text:0000000000CCB55C mov edx, 107h
.text:0000000000CCB561 mov ecx, 2
.text:0000000000CCB566 call sub_BFB2A0
.text:0000000000CCB56B lea rdi, [rbp+var_170]
.text:0000000000CCB572 lea rsi, unk_19F568
.text:0000000000CCB579 mov edx, 11h
.text:0000000000CCB57E call sub_66E360
.text:0000000000CCB583 mov r14, rax
.text:0000000000CCB586 lea rbx, [rbp+var_190]
.text:0000000000CCB58D lea rsi, [rbp+var_40]
.text:0000000000CCB591 mov rdi, rbx
.text:0000000000CCB594 call sub_1706710
.text:0000000000CCB599 movzx edx, [rbp+var_179]
.text:0000000000CCB5A0 test dl, dl
.text:0000000000CCB5A2 jns short loc_CCB5B2
.text:0000000000CCB5A4 mov rbx, [rbp+var_190]
.text:0000000000CCB5AB mov rdx, [rbp+var_188]
.text:0000000000CCB5B2
.text:0000000000CCB5B2 loc_CCB5B2: ; CODE XREF: vul2+A2↑j
.text:0000000000CCB5B2 mov rdi, r14
.text:0000000000CCB5B5 mov rsi, rbx
.text:0000000000CCB5B8 call sub_66E360
.text:0000000000CCB5BD cmp [rbp+var_179], 0
.text:0000000000CCB5C4 jns short loc_CCB5D2
.text:0000000000CCB5C6 mov rdi, [rbp+var_190]
.text:0000000000CCB5CD call free
.text:0000000000CCB5D2
.text:0000000000CCB5D2 loc_CCB5D2: ; CODE XREF: vul2+C4↑j
.text:0000000000CCB5D2 lea rdi, [rbp+var_178]
.text:0000000000CCB5D9 call sub_BFBB10
.text:0000000000CCB5DE
.text:0000000000CCB5DE loc_CCB5DE: ; CODE XREF: vul2+48↑j
.text:0000000000CCB5DE add dword ptr [r15+2Ch], 1
.text:0000000000CCB5E3 mov rdi, r15
.text:0000000000CCB5E6 call sub_CCA290
.text:0000000000CCB5EB lea rdi, [rbp+var_40]
.text:0000000000CCB5EF call sub_B636B0
.text:0000000000CCB5F4 mov rax, fs:28h
.text:0000000000CCB5FD cmp rax, [rbp+var_20]
.text:0000000000CCB601 jnz short loc_CCB611
.text:0000000000CCB603 add rsp, 178h
.text:0000000000CCB60A pop rbx
.text:0000000000CCB60B pop r14
.text:0000000000CCB60D pop r15
.text:0000000000CCB60F pop rbp
.text:0000000000CCB610 retn

漏洞2伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
unsigned __int64 __fastcall vul2(__int64 a1, __int64 a2)
{
__int64 v2; // r14
__int64 *v3; // rbx
__int64 v4; // rdx
__int64 *v6; // [rsp+0h] [rbp-190h]
__int64 v7; // [rsp+8h] [rbp-188h]
unsigned __int8 v8; // [rsp+17h] [rbp-179h]
char v9; // [rsp+18h] [rbp-178h]
char v10; // [rsp+20h] [rbp-170h]
__int128 v11; // [rsp+150h] [rbp-40h]
int v12; // [rsp+160h] [rbp-30h]
unsigned __int64 v13; // [rsp+170h] [rbp-20h]

v13 = __readfsqword(0x28u);
v11 = xmmword_122F40;
v12 = -1431655766;
(*(void (__fastcall **)(__int128 *))(*(_QWORD *)a2 + 48LL))(&v11);// 出现段错误函数指针调用
if ( sub_BFB1B0(2) )
{
sub_BFB2A0((__int64)&v9, (__int64)"../../qnox/msf/msfping.cc", 0x107u, 2);
v2 = sub_66E360(&v10, &unk_19F568, 17LL);
v3 = (__int64 *)&v6;
sub_1706710(&v6, &v11);
v4 = v8;
if ( (v8 & 0x80u) != 0 )
{
v3 = v6;
v4 = v7;
}
sub_66E360(v2, v3, v4);
if ( (v8 & 0x80u) != 0 )
free(v6);
sub_BFBB10(&v9);
}
++*(_DWORD *)(a1 + 44);
sub_CCA290(a1);
sub_B636B0(&v11);
return __readfsqword(0x28u);
}

经过以上调试, 发现目前存在两个段错误漏洞, 应该是多线程处理对象时处理不当造成的, 望腾讯公司进行严格的代码审计与修复

Linux QQ 无用解决闪退的方法

解决方案1

删除掉配置文件即可

https://blog.csdn.net/qq_36462403/article/details/105902227

1
rm -r ~/.config/tencent-qq

经过测试, 无效

解决方案2

https://blog.csdn.net/weixin_33692284/article/details/91508019

经过测试,无效

其他知识补充

gtklib之主事件循环

https://www.cnblogs.com/silvermagic/p/9087881.html

介绍

GLib和GTK+应用的主事件循环管理着所有事件源。这些事件的来源有很多种比如文件描述符(文件、管道或套接字)或超时。新类型的事件源可以通过g_source_attach()函数添加。
为了让多组独立事件源能够在不同的线程中被处理,每个事件源都会关联一个
GMainContext
。一个线程只能运行一个GMainContext,但是在其他线程中能够对事件源进行添加和删除操作。
每个事件源都被赋予了优先级。默认的优先级是G_PRIORITY_DEFAULT(0)。值越小优先级越高,优先级高的事件源优先处理。
Idle函数在没有更高优先级的事件被处理的时候才会执行。
GMainLoop数据类型代表了一个主事件循环。通过g_main_loop_new()来创建GMainLoop对象。在添加完初始事件源后执行g_main_loop_run(),主循环将持续不断的检查每个事件源产生的新事件,然后分发它们,直到处理来自某个事件源的事件的时候触发了g_main_loop_quit()调用退出主循环为止。
GMainLoop实例能够被递归创建。在GTK+应用中经常使用这种方式来显示模态对话框。注意如果一个事件源被添加到一个
GMainContext
,那么它将被所有关联这个GMainContext的主线程检查和分发。
GTK+对这些函数做了些封装,例如gtk_main、gtk_mian_quit和gtk_events_pending。

自定义事件类型

GMainLoop一个不常用的特性就是能够创建一个新的事件源类型,然后当做内置事件源的扩展来使用。一个新的事件源类型通常用来处理GDK事件。通过继承GSource结构来创建一个新的事件源类型。继承产生的新事件源类型表示GSource结构作为新事件源类型的第一个元素然后其他元素紧跟其后。使用g_source_new函数来创建新的事件源类型实例,函数的参数就是新的事件源类型大小。GSourceFuncs决定新的事件源类型的行为。
新的事件源有两种基本方式与GMainContext交互。它们GSourceFuncs中的准备函数能够设置睡眠事件,用来决定主循环下次检测它们的时间。此外事件源也可以使用g_source_add_poll()函数添加文件描述符到GMainContext进行检测。

自定义主循环迭代

执行g_main_context_iteration()函数可以完成GMainContext的单次迭代。在一些情况下,我们可能想获取主循环更多的底层控制细节,我们可以调用**g_main_context_iteration()里的组件函数:g_main_context_prepare()g_main_context_prepare ()g_main_context_query()g_main_context_check()g_main_context_dispatch()**。

Main Context状态

在UNIX系统上,GLib的主循环和**fork()**是不兼容的。

事件源内存管理

有两种可选的方式来管理传递给GSource回调函数用户数据的内存。用户数据就是在调用**g_timeout_add()g_timeout_add_full()g_idle_add()**传入的参数。这些数据通常被timeout或idle回调函数所拥有,比如一个构件或一个网路协议的实现。有些时候这些回调函数会在数据被销毁的后背调用,因为使用了已经被释放的内存,所以这会导致一个错误。

  • 第一种推荐的方法就是保存g_timeout_add()g_source_attach()返回的事件源ID,然后在其维持的用户数据被释放后显示的将其从GMainContext移除。这样就能保证调用这些回调函数的时候,这些用户数据依然有效。
  • 第二种就是保存这些回调函数中的用户数据对象的引用,然后在GDestroyNotify回调函数中释放它。这样就能确保数据对象在事件源最后一次调用然后被释放前一直有效。GDestroyNotify回调函数是GSource函数的一个变体的入参,它在事件源被释放时调用。
    第二条途径有必要提醒下,如果在事件源还没被调用前主循环就结束的情况下,用户数据对象被维持状态是不确定的。

官方文档 gtk库函数

参考:https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html

g_main_context_dispatch ()

1
2
void
g_main_context_dispatch (GMainContext *context);

Dispatches all pending sources.

You must have successfully acquired the context with g_main_context_acquire() before you may call this function.

g_main_context_acquire ()

1
2
gboolean
g_main_context_acquire (GMainContext *context);

Tries to become the owner of the specified context. If some other thread is the owner of the context, returns FALSE immediately. Ownership is properly recursive: the owner can require ownership again and will release ownership when g_main_context_release() is called as many times as g_main_context_acquire().

You must be the owner of a context before you can call g_main_context_prepare(), g_main_context_query(), g_main_context_check(), g_main_context_dispatch().

g_main_context_iteration ()

1
2
3
gboolean
g_main_context_iteration (GMainContext *context,
gboolean may_block);

Runs a single iteration for the given main loop. This involves checking to see if any event sources are ready to be processed, then if no events sources are ready and may_block is TRUE, waiting for a source to become ready, then dispatching the highest priority events sources that are ready. Otherwise, if may_block is FALSE sources are not waited to become ready, only those highest priority events sources will be dispatched (if any), that are ready at this given moment without further waiting.

Note that even when may_block is TRUE, it is still possible for g_main_context_iteration() to return FALSE, since the wait may be interrupted for other reasons than an event source becoming ready.

Parameters

context a GMainContext (if NULL, the default context will be used). [nullable]
may_block whether the call may block.

Returns

TRUE if events were dispatched.

GMainContext

1
typedef struct _GMainContext GMainContext;

The GMainContext struct is an opaque data type representing a set of sources to be handled in a main loop.

打赏点小钱
支付宝 | Alipay
微信 | WeChat