[20261002]oracle Semaphore Arrays Key值的计算2.txt
[20261002]oracle Semaphore Arrays Key值的计算2.txt
--//前面的测试已经确定使用sskgphpjw函数计算Semaphore Arrays Key,继续后面的测试。
1.建立bpftrace脚本跟踪sskgphpjw执行时参数:
$ cat test7.bt
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d ptr=0x%016lx arg0=%s arg1=%d arg2=%d arg3=0x%016lx\n", strftime("%H:%M:%S", nsecs), func,pid,arg0,buf(arg0,50),arg1,arg2,arg3);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%016lx %lu\n", strftime("%H:%M:%S", nsecs), func,pid, retval, retval);
}
$ nm $(which oracle) | egrep "skgmhash|sskgphpjw"
00000000057909b0 T skgmhash
00000000057b5a30 t sskgphpjw
--//小写的t,大写T有什么区别。
2.测试:
--//关闭数据库重启实例:
# bpftrace test7.bt 0
Attached 2 probes
[12:47:02] sskgphpjw pid=8500 ptr=0x00007ffcfebdefe0 arg0=book/u01/app/oracle/product/21.0.0/dbhome_1$\xe6\x7f\x00\x00\xae\x03 arg1=0 arg2=43 arg3=0x00007fe620711c7f
[12:47:02] sskgphpjw pid=8500 return hash_value=0x000000005507207c 1426530428
[12:47:02] sskgphpjw pid=8500 ptr=0x00007ffcfebdefe0 arg0=cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2$\xe6\x7f\x00\x00\xae\x03 arg1=43 arg2=1 arg3=0x000000000000002b
[12:47:02] sskgphpjw pid=8500 return hash_value=0x000000007e0edb60 2114902880
[12:47:02] sskgphpjw pid=8500 ptr=0x00007ffcfebdefe0 arg0=dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3$\xe6\x7f\x00\x00\xae\x03 arg1=43 arg2=0 arg3=0x000000000000002b
[12:47:02] sskgphpjw pid=8500 return hash_value=0x0000000099eaaedc 2582294236
[12:47:02] sskgphpjw pid=8500 ptr=0x00007ffcfebdefe0 arg0=errn2x342dss2rudfoh2surgxfw25413132gekrphb4$\xe6\x7f\x00\x00\xae\x03 arg1=43 arg2=1 arg3=0x000000000000002b
[12:47:02] sskgphpjw pid=8500 return hash_value=0x0000000032fcf5bc 855438780
--//每次执行arg0指针指向的字符串输出顺序都是一样的。
--//arg0=book/u01/app/oracle/product/21.0.0/dbhome_1$\xe6\x7f\x00\x00\xae\x03,参与计算的字符串
--//book/u01/app/oracle/product/21.0.0/dbhome_1,长度43.
--//book是数据库实例,/u01/app/oracle/product/21.0.0/dbhome_1 是ORACLE_HOME环境变量.
--//与前面计算共享内存段的key参数参与计算的字符串类似,只不过oracle Semaphore Arrays Key参与的字符串是sid在前,
--//ORACLE_HOME在后。
--//注意看arg1,arg2值,第一次调用0,43,后面几次是43,1; 43,0; 43,1 ,这里表示什么意思.
--//再来看看arg0的字符串指针,每次地址都是0x00007ffcfebdefe0,而且字符串反复多次测试前面43个字符串都是一样的顺序.
--//昨天测试就卡在这里,在gdb下直接调用sskgphpjw函数:
(gdb) p /x (long int) sskgphpjw((char *)"book/u01/app/oracle/product/21.0.0/dbhome_1",0,43)
$1 = 0x4
(gdb) p /x (long int) sskgphpjw("a",0,43)
$14 = 0x4
--//每次的测试返回都是0x4,不知道问题出在那里。
--//提交sskgphpjw函数的反汇编代码,让deepseek给出答案,简单摘要如下:
根据你给出的 sskgphpjw 反汇编,可以确定:
这个函数实际上只接收 1 个参数:rdi,指向一个结构体/缓冲区。
你之前用 bpftrace 看到的 arg1=0、arg2=43、arg3=... 并不是函数参数,而是调用者遗留在 rsi/rdx/rcx/r8 寄存器里的垃圾值,函
数入口根本没有使用它们。
1. 反汇编解读
入口:
0x57b5a30 <+0>: xchg %ax,%ax
0x57b5a32 <+2>: push %rbp
0x57b5a33 <+3>: mov %rsp,%rbp
0x57b5a36 <+6>: xor %r8d,%r8d
0x57b5a39 <+9>: mov 0x100(%rdi),%rsi ; rsi = *(uint64*)(rdi + 0x100) = 长度
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0x57b5a40 <+16>: xor %r10d,%r10d ; r10 = hash = 0
0x57b5a43 <+19>: xor %ecx,%ecx ; rcx = 0
0x57b5a45 <+21>: test %rsi,%rsi
0x57b5a48 <+24>: jbe 0x57b5bba ; 如果长度 <= 0,跳到最后
0x57b5a4e <+30>: add %rsi,%rdi ; rdi = 原始 rdi + 长度
循环:
asm
0x57b5a51 <+33>: movzbl -0x1(%rcx,%rdi,1),%r9d ; 从字符串末尾向前取字节
...
0x57b5a65 <+53>: dec %rcx ; rcx 递减
...
0x57b5bb1 <+385>: cmp %rsi,%r8
0x57b5bb4 <+388>: jb 0x57b5a51 ; 循环长度次
最后:
asm
0x57b5bba <+394>: shl $0x2,%r10d ; hash <<= 2
0x57b5bbe <+398>: je 0x57b5bc8
0x57b5bc0 <+400>: mov %r10d,%eax
0x57b5bc3 <+403>: mov %rbp,%rsp
0x57b5bc6 <+406>: pop %rbp
0x57b5bc7 <+407>: ret
0x57b5bc8 <+408>: mov $0x4,%r10d ; 如果 hash<<2 == 0,返回 4
0x57b5bce <+414>: jmp 0x57b5bc0
2. 为什么你在 gdb 里调用返回 0x4
p /x (long int) sskgphpjw((char *)"book/u01/app/oracle/product/21.0.0/dbhome_1",0,43)
这里你只传了第一个参数 rdi 为字符串字面量地址。
sskgphpjw 会去读:
*(uint64_t *)(rdi + 0x100)
但字符串字面量后面 +0x100 处并不是长度字段,而是别的内存,很可能是 0 或不可预测值。
如果读到的长度为 0,函数直接走到:
--//相当于指针越界,可能取到0值或者其他值,最大可能是0,导致最后的结果等于4.
0x57b5bba: shl $0x2,%r10d ; r10=0 -> 0
0x57b5bbe: je 0x57b5bc8
0x57b5bc8: mov $0x4,%r10d
于是返回 4。所以不是函数算错,而是你构造的"结构"不对。
3. 正确的 gdb 调用方法
你需要在 gdb 里构造一个合法的结构:
- 起始地址放字符串;
- 起始地址 + 0x100 处放 8 字节长度;
- 然后把起始地址作为唯一参数传给 sskgphpjw。
方法 A:用 malloc + strcpy 构造
在 gdb 中,先让 Oracle 进程运行起来,最好在 sskgphpjw 入口断点命中后,或者程序已经启动到 main 之后。
gdb
(gdb) set $buf = (char *)malloc(0x108)
(gdb) call strcpy($buf, "book/u01/app/oracle/product/21.0.0/dbhome_1")
(gdb) set {unsigned long}($buf + 0x100) = 43
(gdb) p /x (unsigned int)sskgphpjw($buf)
预期输出:
$1 = 0x5507207c
3.重新整理分析:
--//根据deepseek的反馈,实际上仅仅需要1个参数,并且字符串长度实际0x108,rdi的地址实际上指向某个结构体的指针。
--//大小0x108 = 264,其长度放在0x100处,43 = 0x2b,这样构造一个长度264的字符串,1后面跟256-43 = 213个a,然后是
--//\x2b\x0\x0\x0\x0\x0\x0\x0,表示长度43.
(gdb) p /x (long int) sskgphpjw((char *)"book/u01/app/oracle/product/21.0.0/dbhome_1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x2b\x0\x0\x0\x0\x0\x0\x0")
$10 = 0x5507207c
--//完全正确。
--//根据deepseek的反馈执行如下:
(gdb) set $buf = (char *)malloc(0x108)
(gdb) call strcpy($buf, "book/u01/app/oracle/product/21.0.0/dbhome_1")
$11 = 0x1bb795b0 "book/u01/app/oracle/product/21.0.0/dbhome_1"
(gdb) set {unsigned long}($buf + 0x100) = 43
(gdb) p /x (unsigned int)sskgphpjw($buf)
$12 = 0x5507207c
--//计算结果也是一样。
(gdb) call strcpy($buf, "cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2")
$14 = 0x1bb795b0 "cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2"
(gdb) p /x (unsigned int)sskgphpjw($buf)
$15 = 0x7e0edb60
--//与前面bpftrace的输出hash_value=0x000000007e0edb60 2114902880,完全一致。
(gdb) call strcpy($buf, "dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3")
$16 = 0x1bb795b0 "dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3"
(gdb) p /x (unsigned int)sskgphpjw($buf)
$17 = 0x99eaaedc
(gdb) call strcpy($buf, "errn2x342dss2rudfoh2surgxfw25413132gekrphb4")
$18 = 0x1bb795b0 "errn2x342dss2rudfoh2surgxfw25413132gekrphb4"
(gdb) p /x (unsigned int)sskgphpjw($buf)
$19 = 0x32fcf5bc
--//返回值都与前面bpftrace的输出值对应,在带入字符串做运算时发现一个规律,注意看前3个字符boo,以及结尾1个字符1。
book/u01/app/oracle/product/21.0.0/dbhome_1
cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2
dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3
errn2x342dss2rudfoh2surgxfw25413132gekrphb4
--//很明显每次参与运算的ascii码在原来的基础上+1,另外写一篇blog验证。
--//重新写bpftrace脚本:
$ cat sskgphpjw.bt
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
$len = * (uint64 *)(arg0 + 0x100);
printf("[%s] %s pid=%d ptr=0x%016lx len=%lu str=%s\n", strftime("%H:%M:%S", nsecs), func, pid, arg0, $len,buf(arg0,$len));
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%08lx %lu\n", strftime("%H:%M:%S", nsecs), func, pid, retval, retval);
}
# bpftrace sskgphpjw.bt 0
Attached 2 probes
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=book/u01/app/oracle/product/21.0.0/dbhome_1
[16:22:49] sskgphpjw pid=5033 return hash_value=0x5507207c 1426530428
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2
[16:22:49] sskgphpjw pid=5033 return hash_value=0x7e0edb60 2114902880
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3
[16:22:49] sskgphpjw pid=5033 return hash_value=0x99eaaedc 2582294236
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=errn2x342dss2rudfoh2surgxfw25413132gekrphb4
[16:22:49] sskgphpjw pid=5033 return hash_value=0x32fcf5bc 855438780
4.可以做一个简单测试验证以上的测试是否正确:
--//关闭数据库实例,重新定义环境变量如下:
$ export ORACLE_HOME=/u01/app/oracle/product/21.0.0/dbhome_1//
--//结尾加入2个斜线。这样去掉1个斜线还有1个斜线,等于改变了参与字符串运算的变量。
$ rlsql
SQL*Plus: Release 21.0.0.0.0 - Production on Fri Oct 2 16:31:55 2026
Version 21.3.0.0.0
Copyright (c) 1982, 2021, Oracle. All rights reserved.
Connected to an idle instance.
SYS@book> startup nomount
ORACLE instance started.
Total System Global Area 1157625848 bytes
Fixed Size 9684984 bytes
Variable Size 704643072 bytes
Database Buffers 436207616 bytes
Redo Buffers 7090176 bytes
# bpftrace sskgphpjw.bt 0
Attached 2 probes
[16:32:00] sskgphpjw pid=5258 ptr=0x00007ffc853f28e0 len=44 str=book/u01/app/oracle/product/21.0.0/dbhome_1/
[16:32:00] sskgphpjw pid=5258 return hash_value=0xc1335364 3241366372
[16:32:00] sskgphpjw pid=5258 ptr=0x00007ffc853f28e0 len=44 str=cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`20
[16:32:00] sskgphpjw pid=5258 return hash_value=0x02c48134 46432564
[16:32:00] sskgphpjw pid=5258 ptr=0x00007ffc853f28e0 len=44 str=dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga31
[16:32:00] sskgphpjw pid=5258 return hash_value=0x959a7b34 2509929268
[16:32:00] sskgphpjw pid=5258 ptr=0x00007ffc853f28e0 len=44 str=errn2x342dss2rudfoh2surgxfw25413132gekrphb42
[16:32:00] sskgphpjw pid=5258 return hash_value=0x71b8e8f8 1907943672
--//第1个运算的字符串是book/u01/app/oracle/product/21.0.0/dbhome_1/,长度是44.
$ ipcs -a
------ Message Queues --------
key msqid owner perms used-bytes messages
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 44 oracle 600 10485760 34
0x00000000 45 oracle 600 1140850688 34
0x00000000 46 oracle 600 8388608 34
0x9bb1fa1c 47 oracle 600 2097152 34
------ Semaphore Arrays --------
key semid owner perms nsems
0xc1335364 47 oracle 600 250
--//Semaphore Arrays key=0xc1335364,与bpftrace的输出完全一致。
(gdb) p /x (long int) skgmhash("/u01/app/oracle/product/21.0.0/dbhome_1/book",44)
$1 = 0x9bb1fa1c
--//Shared Memory Segments的key0x9bb1fa1c,计算也完全正确。
--//注:带入的ORACLE_HOME删除最后1个斜线,保留1个斜线。
--//这时突然冒出一个想法,很有可能sskgphpjw的算法与skgmhash的算法基本相同。因为前面的测试计算等于0返回4.还有反汇编的代码
--//里面参与运算的数字也出现0xc0bb62ed,0x40bd8ded 数值。
(gdb) p /x (long int) skgmhash("book/u01/app/oracle/product/21.0.0/dbhome_1//",45)
$4 = 0xc1335364
--//哈哈,计算结果完全一致。
--//注:结尾必须带入2个斜线,因为skgmhash函数会丢掉结尾的1个斜线。
(gdb) p /x (long int) skgmhash("book/u01/app/oracle/product/21.0.0/dbhome_1/",44)
$5 = 0x5507207c
(gdb) p /x (long int) skgmhash("book/u01/app/oracle/product/21.0.0/dbhome_1",43)
$6 = 0x5507207c
--//两个计算结果一样,并且正好就是前面的计算结果。
(gdb) p /x (long int) skgmhash("cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`20",44)
$7 = 0x2c48134
--//[16:32:00] sskgphpjw pid=5258 return hash_value=0x02c48134 46432564
5.小结:
--//1.oracle Semaphore Arrays Key值的计算 使用 sskgphpjw函数。
--//2.sskgphpjw的算法与skgmhash的算法基本相同,除了对结尾斜线的处理。
--//3.Semaphore Arrays的key参与计算的字符串是oracle_sid+ORACLE_HOME,Shared Memory Segment的key参与计算的字符串是
--// ORACLE_HOME+oracle_sid.
--// Semaphore Arrays的key是参与计算的字符串, 其asci码+1,再次参与计算尝试,Shared Memory Segment的key计算好的key,在其基
--// 础上+1,+2,+3尝试.
--//4.AI 确实很长强大,善于运用确实大大提供工作效率,节省时间。但是也会犯一些小错误,当然你可以反复与它交流。
--//5.最终按照deepseek的建议以及结合里面的函数修改sskgphpjw.bt脚本如下:
$ cat sskgphpjw.bt
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpwidtokeys
/ $1 == 0 || pid == $1 /
{
printf("\n%s Begin\n",func);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpwidtokeys
/ $1 == 0 || pid == $1 /
{
printf("%s End\n",func);
}
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpbitspersem,
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgph2
/ $1 == 0 || pid == $1 /
{
printf("%s Begin\n",func);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpbitspersem,
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgph2
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%08lx %lu\n", strftime("%H:%M:%S", nsecs), func, pid, retval, retval);
printf("%s End\n",func);
}
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw,
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgph2
/ $1 == 0 || pid == $1 /
{
$len = * (uint64 *)(arg0 + 0x100);
printf("[%s] %s pid=%d ptr=0x%016lx len=%lu str=%s\n", strftime("%H:%M:%S", nsecs), func, pid, arg0, $len,buf(arg0,$len));
//print(ustack);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%08lx %lu\n", strftime("%H:%M:%S", nsecs), func, pid, retval, retval);
}
# bpftrace sskgphpjw.bt 0
Attached 9 probes
sskgpwidtokeys Begin
sskgpbitspersem Begin
[16:00:38] sskgpbitspersem pid=3654 return hash_value=0x0000000e 14
[16:00:38] sskgphpjw pid=3654 ptr=0x00007ffd6d7d37e0 len=43 str=book/u01/app/oracle/product/21.0.0/dbhome_1
[16:00:38] sskgphpjw pid=3654 return hash_value=0x5507207c 1426530428
[16:00:38] sskgphpjw pid=3654 ptr=0x00007ffd6d7d37e0 len=43 str=cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2
[16:00:38] sskgphpjw pid=3654 return hash_value=0x7e0edb60 2114902880
[16:00:38] sskgphpjw pid=3654 ptr=0x00007ffd6d7d37e0 len=43 str=dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3
[16:00:38] sskgphpjw pid=3654 return hash_value=0x99eaaedc 2582294236
[16:00:38] sskgphpjw pid=3654 ptr=0x00007ffd6d7d37e0 len=43 str=errn2x342dss2rudfoh2surgxfw25413132gekrphb4
[16:00:38] sskgphpjw pid=3654 return hash_value=0x32fcf5bc 855438780
sskgph2 Begin
[16:00:38] sskgph2 pid=3654 ptr=0x00007ffd6d7d4038 len=43 str=book/u01/app/oracle/product/21.0.0/dbhome_1
[16:00:38] sskgph2 pid=3654 return hash_value=0x9937c3fd 2570568701
sskgpwidtokeys End
--//前面的测试已经确定使用sskgphpjw函数计算Semaphore Arrays Key,继续后面的测试。
1.建立bpftrace脚本跟踪sskgphpjw执行时参数:
$ cat test7.bt
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d ptr=0x%016lx arg0=%s arg1=%d arg2=%d arg3=0x%016lx\n", strftime("%H:%M:%S", nsecs), func,pid,arg0,buf(arg0,50),arg1,arg2,arg3);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%016lx %lu\n", strftime("%H:%M:%S", nsecs), func,pid, retval, retval);
}
$ nm $(which oracle) | egrep "skgmhash|sskgphpjw"
00000000057909b0 T skgmhash
00000000057b5a30 t sskgphpjw
--//小写的t,大写T有什么区别。
2.测试:
--//关闭数据库重启实例:
# bpftrace test7.bt 0
Attached 2 probes
[12:47:02] sskgphpjw pid=8500 ptr=0x00007ffcfebdefe0 arg0=book/u01/app/oracle/product/21.0.0/dbhome_1$\xe6\x7f\x00\x00\xae\x03 arg1=0 arg2=43 arg3=0x00007fe620711c7f
[12:47:02] sskgphpjw pid=8500 return hash_value=0x000000005507207c 1426530428
[12:47:02] sskgphpjw pid=8500 ptr=0x00007ffcfebdefe0 arg0=cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2$\xe6\x7f\x00\x00\xae\x03 arg1=43 arg2=1 arg3=0x000000000000002b
[12:47:02] sskgphpjw pid=8500 return hash_value=0x000000007e0edb60 2114902880
[12:47:02] sskgphpjw pid=8500 ptr=0x00007ffcfebdefe0 arg0=dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3$\xe6\x7f\x00\x00\xae\x03 arg1=43 arg2=0 arg3=0x000000000000002b
[12:47:02] sskgphpjw pid=8500 return hash_value=0x0000000099eaaedc 2582294236
[12:47:02] sskgphpjw pid=8500 ptr=0x00007ffcfebdefe0 arg0=errn2x342dss2rudfoh2surgxfw25413132gekrphb4$\xe6\x7f\x00\x00\xae\x03 arg1=43 arg2=1 arg3=0x000000000000002b
[12:47:02] sskgphpjw pid=8500 return hash_value=0x0000000032fcf5bc 855438780
--//每次执行arg0指针指向的字符串输出顺序都是一样的。
--//arg0=book/u01/app/oracle/product/21.0.0/dbhome_1$\xe6\x7f\x00\x00\xae\x03,参与计算的字符串
--//book/u01/app/oracle/product/21.0.0/dbhome_1,长度43.
--//book是数据库实例,/u01/app/oracle/product/21.0.0/dbhome_1 是ORACLE_HOME环境变量.
--//与前面计算共享内存段的key参数参与计算的字符串类似,只不过oracle Semaphore Arrays Key参与的字符串是sid在前,
--//ORACLE_HOME在后。
--//注意看arg1,arg2值,第一次调用0,43,后面几次是43,1; 43,0; 43,1 ,这里表示什么意思.
--//再来看看arg0的字符串指针,每次地址都是0x00007ffcfebdefe0,而且字符串反复多次测试前面43个字符串都是一样的顺序.
--//昨天测试就卡在这里,在gdb下直接调用sskgphpjw函数:
(gdb) p /x (long int) sskgphpjw((char *)"book/u01/app/oracle/product/21.0.0/dbhome_1",0,43)
$1 = 0x4
(gdb) p /x (long int) sskgphpjw("a",0,43)
$14 = 0x4
--//每次的测试返回都是0x4,不知道问题出在那里。
--//提交sskgphpjw函数的反汇编代码,让deepseek给出答案,简单摘要如下:
根据你给出的 sskgphpjw 反汇编,可以确定:
这个函数实际上只接收 1 个参数:rdi,指向一个结构体/缓冲区。
你之前用 bpftrace 看到的 arg1=0、arg2=43、arg3=... 并不是函数参数,而是调用者遗留在 rsi/rdx/rcx/r8 寄存器里的垃圾值,函
数入口根本没有使用它们。
1. 反汇编解读
入口:
0x57b5a30 <+0>: xchg %ax,%ax
0x57b5a32 <+2>: push %rbp
0x57b5a33 <+3>: mov %rsp,%rbp
0x57b5a36 <+6>: xor %r8d,%r8d
0x57b5a39 <+9>: mov 0x100(%rdi),%rsi ; rsi = *(uint64*)(rdi + 0x100) = 长度
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0x57b5a40 <+16>: xor %r10d,%r10d ; r10 = hash = 0
0x57b5a43 <+19>: xor %ecx,%ecx ; rcx = 0
0x57b5a45 <+21>: test %rsi,%rsi
0x57b5a48 <+24>: jbe 0x57b5bba ; 如果长度 <= 0,跳到最后
0x57b5a4e <+30>: add %rsi,%rdi ; rdi = 原始 rdi + 长度
循环:
asm
0x57b5a51 <+33>: movzbl -0x1(%rcx,%rdi,1),%r9d ; 从字符串末尾向前取字节
...
0x57b5a65 <+53>: dec %rcx ; rcx 递减
...
0x57b5bb1 <+385>: cmp %rsi,%r8
0x57b5bb4 <+388>: jb 0x57b5a51 ; 循环长度次
最后:
asm
0x57b5bba <+394>: shl $0x2,%r10d ; hash <<= 2
0x57b5bbe <+398>: je 0x57b5bc8
0x57b5bc0 <+400>: mov %r10d,%eax
0x57b5bc3 <+403>: mov %rbp,%rsp
0x57b5bc6 <+406>: pop %rbp
0x57b5bc7 <+407>: ret
0x57b5bc8 <+408>: mov $0x4,%r10d ; 如果 hash<<2 == 0,返回 4
0x57b5bce <+414>: jmp 0x57b5bc0
2. 为什么你在 gdb 里调用返回 0x4
p /x (long int) sskgphpjw((char *)"book/u01/app/oracle/product/21.0.0/dbhome_1",0,43)
这里你只传了第一个参数 rdi 为字符串字面量地址。
sskgphpjw 会去读:
*(uint64_t *)(rdi + 0x100)
但字符串字面量后面 +0x100 处并不是长度字段,而是别的内存,很可能是 0 或不可预测值。
如果读到的长度为 0,函数直接走到:
--//相当于指针越界,可能取到0值或者其他值,最大可能是0,导致最后的结果等于4.
0x57b5bba: shl $0x2,%r10d ; r10=0 -> 0
0x57b5bbe: je 0x57b5bc8
0x57b5bc8: mov $0x4,%r10d
于是返回 4。所以不是函数算错,而是你构造的"结构"不对。
3. 正确的 gdb 调用方法
你需要在 gdb 里构造一个合法的结构:
- 起始地址放字符串;
- 起始地址 + 0x100 处放 8 字节长度;
- 然后把起始地址作为唯一参数传给 sskgphpjw。
方法 A:用 malloc + strcpy 构造
在 gdb 中,先让 Oracle 进程运行起来,最好在 sskgphpjw 入口断点命中后,或者程序已经启动到 main 之后。
gdb
(gdb) set $buf = (char *)malloc(0x108)
(gdb) call strcpy($buf, "book/u01/app/oracle/product/21.0.0/dbhome_1")
(gdb) set {unsigned long}($buf + 0x100) = 43
(gdb) p /x (unsigned int)sskgphpjw($buf)
预期输出:
$1 = 0x5507207c
3.重新整理分析:
--//根据deepseek的反馈,实际上仅仅需要1个参数,并且字符串长度实际0x108,rdi的地址实际上指向某个结构体的指针。
--//大小0x108 = 264,其长度放在0x100处,43 = 0x2b,这样构造一个长度264的字符串,1后面跟256-43 = 213个a,然后是
--//\x2b\x0\x0\x0\x0\x0\x0\x0,表示长度43.
(gdb) p /x (long int) sskgphpjw((char *)"book/u01/app/oracle/product/21.0.0/dbhome_1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x2b\x0\x0\x0\x0\x0\x0\x0")
$10 = 0x5507207c
--//完全正确。
--//根据deepseek的反馈执行如下:
(gdb) set $buf = (char *)malloc(0x108)
(gdb) call strcpy($buf, "book/u01/app/oracle/product/21.0.0/dbhome_1")
$11 = 0x1bb795b0 "book/u01/app/oracle/product/21.0.0/dbhome_1"
(gdb) set {unsigned long}($buf + 0x100) = 43
(gdb) p /x (unsigned int)sskgphpjw($buf)
$12 = 0x5507207c
--//计算结果也是一样。
(gdb) call strcpy($buf, "cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2")
$14 = 0x1bb795b0 "cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2"
(gdb) p /x (unsigned int)sskgphpjw($buf)
$15 = 0x7e0edb60
--//与前面bpftrace的输出hash_value=0x000000007e0edb60 2114902880,完全一致。
(gdb) call strcpy($buf, "dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3")
$16 = 0x1bb795b0 "dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3"
(gdb) p /x (unsigned int)sskgphpjw($buf)
$17 = 0x99eaaedc
(gdb) call strcpy($buf, "errn2x342dss2rudfoh2surgxfw25413132gekrphb4")
$18 = 0x1bb795b0 "errn2x342dss2rudfoh2surgxfw25413132gekrphb4"
(gdb) p /x (unsigned int)sskgphpjw($buf)
$19 = 0x32fcf5bc
--//返回值都与前面bpftrace的输出值对应,在带入字符串做运算时发现一个规律,注意看前3个字符boo,以及结尾1个字符1。
book/u01/app/oracle/product/21.0.0/dbhome_1
cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2
dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3
errn2x342dss2rudfoh2surgxfw25413132gekrphb4
--//很明显每次参与运算的ascii码在原来的基础上+1,另外写一篇blog验证。
--//重新写bpftrace脚本:
$ cat sskgphpjw.bt
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
$len = * (uint64 *)(arg0 + 0x100);
printf("[%s] %s pid=%d ptr=0x%016lx len=%lu str=%s\n", strftime("%H:%M:%S", nsecs), func, pid, arg0, $len,buf(arg0,$len));
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%08lx %lu\n", strftime("%H:%M:%S", nsecs), func, pid, retval, retval);
}
# bpftrace sskgphpjw.bt 0
Attached 2 probes
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=book/u01/app/oracle/product/21.0.0/dbhome_1
[16:22:49] sskgphpjw pid=5033 return hash_value=0x5507207c 1426530428
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2
[16:22:49] sskgphpjw pid=5033 return hash_value=0x7e0edb60 2114902880
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3
[16:22:49] sskgphpjw pid=5033 return hash_value=0x99eaaedc 2582294236
[16:22:49] sskgphpjw pid=5033 ptr=0x00007ffed434d0e0 len=43 str=errn2x342dss2rudfoh2surgxfw25413132gekrphb4
[16:22:49] sskgphpjw pid=5033 return hash_value=0x32fcf5bc 855438780
4.可以做一个简单测试验证以上的测试是否正确:
--//关闭数据库实例,重新定义环境变量如下:
$ export ORACLE_HOME=/u01/app/oracle/product/21.0.0/dbhome_1//
--//结尾加入2个斜线。这样去掉1个斜线还有1个斜线,等于改变了参与字符串运算的变量。
$ rlsql
SQL*Plus: Release 21.0.0.0.0 - Production on Fri Oct 2 16:31:55 2026
Version 21.3.0.0.0
Copyright (c) 1982, 2021, Oracle. All rights reserved.
Connected to an idle instance.
SYS@book> startup nomount
ORACLE instance started.
Total System Global Area 1157625848 bytes
Fixed Size 9684984 bytes
Variable Size 704643072 bytes
Database Buffers 436207616 bytes
Redo Buffers 7090176 bytes
# bpftrace sskgphpjw.bt 0
Attached 2 probes
[16:32:00] sskgphpjw pid=5258 ptr=0x00007ffc853f28e0 len=44 str=book/u01/app/oracle/product/21.0.0/dbhome_1/
[16:32:00] sskgphpjw pid=5258 return hash_value=0xc1335364 3241366372
[16:32:00] sskgphpjw pid=5258 ptr=0x00007ffc853f28e0 len=44 str=cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`20
[16:32:00] sskgphpjw pid=5258 return hash_value=0x02c48134 46432564
[16:32:00] sskgphpjw pid=5258 ptr=0x00007ffc853f28e0 len=44 str=dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga31
[16:32:00] sskgphpjw pid=5258 return hash_value=0x959a7b34 2509929268
[16:32:00] sskgphpjw pid=5258 ptr=0x00007ffc853f28e0 len=44 str=errn2x342dss2rudfoh2surgxfw25413132gekrphb42
[16:32:00] sskgphpjw pid=5258 return hash_value=0x71b8e8f8 1907943672
--//第1个运算的字符串是book/u01/app/oracle/product/21.0.0/dbhome_1/,长度是44.
$ ipcs -a
------ Message Queues --------
key msqid owner perms used-bytes messages
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 44 oracle 600 10485760 34
0x00000000 45 oracle 600 1140850688 34
0x00000000 46 oracle 600 8388608 34
0x9bb1fa1c 47 oracle 600 2097152 34
------ Semaphore Arrays --------
key semid owner perms nsems
0xc1335364 47 oracle 600 250
--//Semaphore Arrays key=0xc1335364,与bpftrace的输出完全一致。
(gdb) p /x (long int) skgmhash("/u01/app/oracle/product/21.0.0/dbhome_1/book",44)
$1 = 0x9bb1fa1c
--//Shared Memory Segments的key0x9bb1fa1c,计算也完全正确。
--//注:带入的ORACLE_HOME删除最后1个斜线,保留1个斜线。
--//这时突然冒出一个想法,很有可能sskgphpjw的算法与skgmhash的算法基本相同。因为前面的测试计算等于0返回4.还有反汇编的代码
--//里面参与运算的数字也出现0xc0bb62ed,0x40bd8ded 数值。
(gdb) p /x (long int) skgmhash("book/u01/app/oracle/product/21.0.0/dbhome_1//",45)
$4 = 0xc1335364
--//哈哈,计算结果完全一致。
--//注:结尾必须带入2个斜线,因为skgmhash函数会丢掉结尾的1个斜线。
(gdb) p /x (long int) skgmhash("book/u01/app/oracle/product/21.0.0/dbhome_1/",44)
$5 = 0x5507207c
(gdb) p /x (long int) skgmhash("book/u01/app/oracle/product/21.0.0/dbhome_1",43)
$6 = 0x5507207c
--//两个计算结果一样,并且正好就是前面的计算结果。
(gdb) p /x (long int) skgmhash("cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`20",44)
$7 = 0x2c48134
--//[16:32:00] sskgphpjw pid=5258 return hash_value=0x02c48134 46432564
5.小结:
--//1.oracle Semaphore Arrays Key值的计算 使用 sskgphpjw函数。
--//2.sskgphpjw的算法与skgmhash的算法基本相同,除了对结尾斜线的处理。
--//3.Semaphore Arrays的key参与计算的字符串是oracle_sid+ORACLE_HOME,Shared Memory Segment的key参与计算的字符串是
--// ORACLE_HOME+oracle_sid.
--// Semaphore Arrays的key是参与计算的字符串, 其asci码+1,再次参与计算尝试,Shared Memory Segment的key计算好的key,在其基
--// 础上+1,+2,+3尝试.
--//4.AI 确实很长强大,善于运用确实大大提供工作效率,节省时间。但是也会犯一些小错误,当然你可以反复与它交流。
--//5.最终按照deepseek的建议以及结合里面的函数修改sskgphpjw.bt脚本如下:
$ cat sskgphpjw.bt
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpwidtokeys
/ $1 == 0 || pid == $1 /
{
printf("\n%s Begin\n",func);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpwidtokeys
/ $1 == 0 || pid == $1 /
{
printf("%s End\n",func);
}
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpbitspersem,
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgph2
/ $1 == 0 || pid == $1 /
{
printf("%s Begin\n",func);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgpbitspersem,
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgph2
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%08lx %lu\n", strftime("%H:%M:%S", nsecs), func, pid, retval, retval);
printf("%s End\n",func);
}
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw,
uprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgph2
/ $1 == 0 || pid == $1 /
{
$len = * (uint64 *)(arg0 + 0x100);
printf("[%s] %s pid=%d ptr=0x%016lx len=%lu str=%s\n", strftime("%H:%M:%S", nsecs), func, pid, arg0, $len,buf(arg0,$len));
//print(ustack);
}
uretprobe:/u01/app/oracle/product/21.0.0/dbhome_1/bin/oracle:sskgphpjw
/ $1 == 0 || pid == $1 /
{
printf("[%s] %s pid=%d return hash_value=0x%08lx %lu\n", strftime("%H:%M:%S", nsecs), func, pid, retval, retval);
}
# bpftrace sskgphpjw.bt 0
Attached 9 probes
sskgpwidtokeys Begin
sskgpbitspersem Begin
[16:00:38] sskgpbitspersem pid=3654 return hash_value=0x0000000e 14
[16:00:38] sskgphpjw pid=3654 ptr=0x00007ffd6d7d37e0 len=43 str=book/u01/app/oracle/product/21.0.0/dbhome_1
[16:00:38] sskgphpjw pid=3654 return hash_value=0x5507207c 1426530428
[16:00:38] sskgphpjw pid=3654 ptr=0x00007ffd6d7d37e0 len=43 str=cppl0v120bqq0psbdmf0qspevdu032/1/10ecipnf`2
[16:00:38] sskgphpjw pid=3654 return hash_value=0x7e0edb60 2114902880
[16:00:38] sskgphpjw pid=3654 ptr=0x00007ffd6d7d37e0 len=43 str=dqqm1w231crr1qtceng1rtqfwev14302021fdjqoga3
[16:00:38] sskgphpjw pid=3654 return hash_value=0x99eaaedc 2582294236
[16:00:38] sskgphpjw pid=3654 ptr=0x00007ffd6d7d37e0 len=43 str=errn2x342dss2rudfoh2surgxfw25413132gekrphb4
[16:00:38] sskgphpjw pid=3654 return hash_value=0x32fcf5bc 855438780
sskgph2 Begin
[16:00:38] sskgph2 pid=3654 ptr=0x00007ffd6d7d4038 len=43 str=book/u01/app/oracle/product/21.0.0/dbhome_1
[16:00:38] sskgph2 pid=3654 return hash_value=0x9937c3fd 2570568701
sskgpwidtokeys End
浙公网安备 33010602011771号