免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3816 | 回复: 3
打印 上一主题 下一主题

[FreeBSD] 调用一个函数,当函数返回时修改了上层函数的参数地址,不知为何? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-03-25 20:25 |只看该作者 |倒序浏览
在查看QQ的加密算法时,写了一个解码的测试程序,该程序运行时段错误异常终止。程序如下:

  1. //main

  2. #include "crypt.h"
  3. #include <stdio.h>

  4. int main(int argc,char **argv)
  5. {
  6.   unsigned char key[]={ 0xc8, 0x55, 0x40, 0x00, 0xab, 0x95, 0x05, 0x63, 0xae, 0x4b, 0xe6, 0xec, 0xc7, 0x22, 0x38, 0xb3};
  7.   
  8.   
  9.   unsigned char dest[] = {0x15, 0xe5,
  10.                           0x63, 0x0c,0x83,  0x58, 0x32,  0xf0, 0xe0, 0x7e, 0x1b, 0x76, 0x90, 0xe3,
  11.                           0x88, 0x03, 0xe1, 0x97, 0x38,  0x5f, 0xdf, 0xa5, 0x76, 0xd1 };
  12.   unsigned char decrypt[1024]={0};

  13.   
  14.   int len = 1024;
  15.   int i=0;

  16.   qq_decrypt(dest,24,key,decrypt,&len);

  17.   for(;i<len;i++){
  18.     printf("%x,",decrypt[i]);

  19.   }
  20.   printf("\n");
  21.    
  22.   
  23.   return 0;
  24.   
  25. }

  26. //crypt.c


  27. #ifndef _WIN32
  28. #include <arpa/inet.h>
  29. #else
  30. #include "win32dep.h"
  31. #endif

  32. #include <string.h>

  33. #include "crypt.h"

  34. /*****************************************************************************/
  35. void qq_encipher(unsigned long *const v, const unsigned long *const k, unsigned long *const w)
  36. {
  37.         register unsigned long y = ntohl(v[0]), z = ntohl(v[1]), a = ntohl(k[0]), b = ntohl(k[1]), c = ntohl(k[2]), d = ntohl(k[3]), n = 0x10, sum = 0, delta = 0x9E3779B9&0xFFFFFFFF;        /*  0x9E3779B9 - 0x100000000 = -0x61C88647 */

  38.         while (n-- > 0) {
  39.                 sum += delta;
  40.                 sum &=0xFFFFFFFF;
  41.                 y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);
  42.                 z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);
  43.         }                        // while

  44.         w[0] = htonl(y);
  45.         w[1] = htonl(z);
  46. }                                // qq_enciper

  47. /*****************************************************************************/
  48. void qq_decipher(unsigned long *const v, const unsigned long *const k, unsigned long *const w)
  49. {
  50.         register unsigned long y = ntohl(v[0]), z = ntohl(v[1]), a = ntohl(k[0]), b = ntohl(k[1]), c = ntohl(k[2]), d = ntohl(k[3]), n = 0x10, sum = 0xE3779B90,        // why this ? must be related with n value
  51.             delta = 0x9E3779B9;

  52.         /* sum = delta<<5, in general sum = delta * n */
  53.         while (n-- > 0) {
  54.                 z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);
  55.                 y -= ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);
  56.                 sum -= delta;
  57.         }

  58.         w[0] = htonl(y);
  59.         w[1] = htonl(z);
  60. }                                // qq_decipher

  61. /********************************************************************
  62. * encrypt part
  63. *******************************************************************/

  64. void qq_encrypt(unsigned char *instr, int instrlen, unsigned char *key, unsigned char *outstr, int *outstrlen_prt)
  65. {
  66.         unsigned char plain[8],        // plain text buffer
  67.          plain_pre_8[8],        // plain text buffer, previous 8 bytes
  68.         *crypted,                // crypted text
  69.         *crypted_pre_8,                // crypted test, previous 8 bytes
  70.         *inp;                        // current position in instr
  71.         int pos_in_byte = 1,        // loop in the byte
  72.             is_header = 1,        // header is one byte
  73.             count = 0,                // number of bytes being crypted
  74.             padding = 0;        // number of padding stuff

  75.         int rand(void) {        // it can be the real random seed function
  76.                 return 0xdead;
  77.         }                        // override with number, convenient for debug

  78.   /*** we encrypt every eight byte ***/
  79.         void encrypt_every_8_byte(void) {
  80.                 for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
  81.                         if (is_header) {
  82.                                 plain[pos_in_byte] ^= plain_pre_8[pos_in_byte];
  83.                         } else {
  84.                                 plain[pos_in_byte] ^= crypted_pre_8[pos_in_byte];
  85.                         }
  86.                 }                // prepare plain text
  87.                 qq_encipher((unsigned long *) plain, (unsigned long *) key, (unsigned long *) crypted);        // encrypt it

  88.                 for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
  89.                         crypted[pos_in_byte] ^= plain_pre_8[pos_in_byte];
  90.                 }
  91.                 memcpy(plain_pre_8, plain, 8 );        // prepare next

  92.                 crypted_pre_8 = crypted;        // store position of previous 8 byte
  93.                 crypted += 8;        // prepare next output
  94.                 count += 8;        // outstrlen increase by 8
  95.                 pos_in_byte = 0;        // back to start
  96.                 is_header = 0;        // and exit header
  97.         }                        // encrypt_every_8_byte

  98.         pos_in_byte = (instrlen + 0x0a) % 8;        // header padding decided by instrlen
  99.         if (pos_in_byte) {
  100.                 pos_in_byte = 8 - pos_in_byte;
  101.         }
  102.         plain[0] = (rand() & 0xf8 ) | pos_in_byte;

  103.         memset(plain + 1, rand() & 0xff, pos_in_byte++);
  104.         memset(plain_pre_8, 0x00, sizeof(plain_pre_8 ));

  105.         crypted = crypted_pre_8 = outstr;

  106.         padding = 1;                // pad some stuff in header
  107.         while (padding <= 2) {        // at most two byte
  108.                 if (pos_in_byte < 8 ) {
  109.                         plain[pos_in_byte++] = rand() & 0xff;
  110.                         padding++;
  111.                 }
  112.                 if (pos_in_byte == 8 ) {
  113.                         encrypt_every_8_byte();
  114.                 }
  115.         }

  116.         inp = instr;
  117.         while (instrlen > 0) {
  118.                 if (pos_in_byte < 8 ) {
  119.                         plain[pos_in_byte++] = *(inp++);
  120.                         instrlen--;
  121.                 }
  122.                 if (pos_in_byte == 8 ) {
  123.                         encrypt_every_8_byte();
  124.                 }
  125.         }

  126.         padding = 1;                // pad some stuff in tailer
  127.         while (padding <= 7) {        // at most sever byte
  128.                 if (pos_in_byte < 8 ) {
  129.                         plain[pos_in_byte++] = 0x00;
  130.                         padding++;
  131.                 }
  132.                 if (pos_in_byte == 8) {
  133.                         encrypt_every_8_byte();
  134.                 }
  135.         }

  136.         *outstrlen_prt = count;
  137. }                                // qq_encrypt


  138. /********************************************************************
  139. * [decrypt part]
  140. * return 0 if failed, otherwise return 1
  141. ********************************************************************/

  142. int qq_decrypt(unsigned char *instr, int instrlen, unsigned char *key, unsigned char *outstr, int [color=green]*outstrlen_ptr[/color])
  143. {
  144.         unsigned char decrypted[8], m[8], *crypt_buff, *crypt_buff_pre_8, *outp;
  145.         int count, context_start, pos_in_byte, padding;


  146.         int decrypt_every_8_byte(void) {
  147.                 for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
  148.                         if (context_start + pos_in_byte >= instrlen)
  149.                                 return 1;
  150.                         decrypted[pos_in_byte] ^= crypt_buff[pos_in_byte];
  151.                 }
  152.                 qq_decipher((unsigned long *) decrypted, (unsigned long *) key, (unsigned long *) decrypted);

  153.                 context_start += 8;
  154.                 crypt_buff += 8;
  155.                 pos_in_byte = 0;
  156.                 return 1;
  157.         }                        // decrypt_every_8_byte

  158.         // at least 16 bytes and %8 == 0
  159.         if ((instrlen % 8) || (instrlen < 16))
  160.                 return 0;
  161.         // get information from header

  162.         [color=red]qq_decipher((unsigned long *) instr, (unsigned long *) key, (unsigned long *) decrypted);
  163. [/color]      
  164.       
  165.         pos_in_byte = decrypted[0] & 0x7;
  166.        
  167.         count = instrlen - pos_in_byte - 10;        // this is the plaintext length
  168.         // return if outstr buffer is not large enought or error plaintext length

  169.         if (*outstrlen_ptr < count || count < 0)
  170.                 return 0;

  171.         memset(m, 0, 8);
  172.         crypt_buff_pre_8 = m;
  173.         *outstrlen_ptr = count;        // everything is ok! set return string length

  174.         crypt_buff = instr + 8;        // address of real data start
  175.         context_start = 8;        // context is at the second 8 byte
  176.         pos_in_byte++;                // start of paddng stuff

  177.         padding = 1;                // at least one in header
  178.         while (padding <= 2) {        // there are 2 byte padding stuff in header
  179.                 if (pos_in_byte < 8) {        // bypass the padding stuff, none sense data
  180.                         pos_in_byte++;
  181.                         padding++;
  182.                 }
  183.                 if (pos_in_byte == 8) {
  184.                         crypt_buff_pre_8 = instr;
  185.                         if (!decrypt_every_8_byte())
  186.                                 return 0;
  187.                 }
  188.         }                        // while

  189.         outp = outstr;
  190.         while (count != 0) {
  191.                 if (pos_in_byte < 8) {
  192.                         *outp = crypt_buff_pre_8[pos_in_byte] ^ decrypted[pos_in_byte];
  193.                         outp++;
  194.                         count--;
  195.                         pos_in_byte++;
  196.                 }
  197.                 if (pos_in_byte == 8) {
  198.                         crypt_buff_pre_8 = crypt_buff - 8;
  199.                         if (!decrypt_every_8_byte())
  200.                                 return 0;
  201.                 }
  202.         }                        // while

  203.         for (padding = 1; padding < 8; padding++) {
  204.                 if (pos_in_byte < 8) {
  205.                         if (crypt_buff_pre_8[pos_in_byte] ^ decrypted[pos_in_byte])
  206.                                 return 0;
  207.                         pos_in_byte++;
  208.                 }
  209.                 if (pos_in_byte == 8) {
  210.                         crypt_buff_pre_8 = crypt_buff;
  211.                         if (!decrypt_every_8_byte())
  212.                                 return 0;
  213.                 }
  214.         }                        // for
  215.         return 1;
  216. }                                // qq_decrypt

复制代码


gdb调试发现当调用qq_decipher函数返回时修改了outstrlen_ptr的地址,应该说outstrlen_ptr是上层函数的入参,是保存在栈中的,程序中也没有修改该地址的地方,不知那里修改了该地址?
还请高手指教

使用平台:FreeBSD 6.1 AMD64

[ 本帖最后由 free_ever 于 2007-3-25 20:32 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2007-03-25 21:19 |只看该作者
实在没功夫去看这么一长串的代码,你可以仔细检查有无栈越界访问的可能,并在必要时设置watchpoint来跟踪对变量的修改。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
3 [报告]
发表于 2007-03-25 22:43 |只看该作者
粗略看了一下程序,好像调用 qq_decipher函数返回时并没有修改outstrlen_ptr的地址,不过在整个程序中确实修改了.看这个地方:

  1.        *outstrlen_ptr = count;        // everything is ok! set return string length
复制代码

论坛徽章:
0
4 [报告]
发表于 2007-04-08 21:26 |只看该作者
*outstrlen_ptr = count;只是修改outstrlen_ptr所指向的地址的值,并不会修改outstrlen_ptr的本身的值。

使用watch发现:

  调用qq_decrypt函数
    时outstrlen_ptr=0x7fffffffe31c
  从qq_decipher函数返回时outstrlen_ptr的值发生了变化.

Old value = (int *) 0x7fffffffe31c
New value = (int *) 0xc0ca0318
qq_decipher (v=0x7fffffffe720, k=0x7fffffffe740, w=0x7fffffffe2d0) at crypt.c:84


查询qq_decrypt函数中的变量decrypted的地址是

(gdb) p &decrypted
$27 = (unsigned char (*)[8]) 0x7fffffffe2d0


函数qq_decipher返回后outstrlen_ptr的值被修改了,也就是说栈被越界修改,导致outstrlen_ptr指向不可访问的地址。怎么会遇上这种鸟事。我就很迷茫.

[ 本帖最后由 free_ever 于 2007-4-8 21:30 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP