- 论坛徽章:
- 0
|
在查看QQ的加密算法时,写了一个解码的测试程序,该程序运行时段错误异常终止。程序如下:
- //main
- #include "crypt.h"
- #include <stdio.h>
- int main(int argc,char **argv)
- {
- unsigned char key[]={ 0xc8, 0x55, 0x40, 0x00, 0xab, 0x95, 0x05, 0x63, 0xae, 0x4b, 0xe6, 0xec, 0xc7, 0x22, 0x38, 0xb3};
-
-
- unsigned char dest[] = {0x15, 0xe5,
- 0x63, 0x0c,0x83, 0x58, 0x32, 0xf0, 0xe0, 0x7e, 0x1b, 0x76, 0x90, 0xe3,
- 0x88, 0x03, 0xe1, 0x97, 0x38, 0x5f, 0xdf, 0xa5, 0x76, 0xd1 };
- unsigned char decrypt[1024]={0};
-
- int len = 1024;
- int i=0;
- qq_decrypt(dest,24,key,decrypt,&len);
- for(;i<len;i++){
- printf("%x,",decrypt[i]);
-
- }
- printf("\n");
-
-
- return 0;
-
- }
- //crypt.c
- #ifndef _WIN32
- #include <arpa/inet.h>
- #else
- #include "win32dep.h"
- #endif
- #include <string.h>
- #include "crypt.h"
- /*****************************************************************************/
- void qq_encipher(unsigned long *const v, const unsigned long *const k, unsigned long *const w)
- {
- 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 */
- while (n-- > 0) {
- sum += delta;
- sum &=0xFFFFFFFF;
- y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);
- z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);
- } // while
- w[0] = htonl(y);
- w[1] = htonl(z);
- } // qq_enciper
- /*****************************************************************************/
- void qq_decipher(unsigned long *const v, const unsigned long *const k, unsigned long *const w)
- {
- 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
- delta = 0x9E3779B9;
- /* sum = delta<<5, in general sum = delta * n */
- while (n-- > 0) {
- z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);
- y -= ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);
- sum -= delta;
- }
- w[0] = htonl(y);
- w[1] = htonl(z);
- } // qq_decipher
- /********************************************************************
- * encrypt part
- *******************************************************************/
- void qq_encrypt(unsigned char *instr, int instrlen, unsigned char *key, unsigned char *outstr, int *outstrlen_prt)
- {
- unsigned char plain[8], // plain text buffer
- plain_pre_8[8], // plain text buffer, previous 8 bytes
- *crypted, // crypted text
- *crypted_pre_8, // crypted test, previous 8 bytes
- *inp; // current position in instr
- int pos_in_byte = 1, // loop in the byte
- is_header = 1, // header is one byte
- count = 0, // number of bytes being crypted
- padding = 0; // number of padding stuff
- int rand(void) { // it can be the real random seed function
- return 0xdead;
- } // override with number, convenient for debug
- /*** we encrypt every eight byte ***/
- void encrypt_every_8_byte(void) {
- for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
- if (is_header) {
- plain[pos_in_byte] ^= plain_pre_8[pos_in_byte];
- } else {
- plain[pos_in_byte] ^= crypted_pre_8[pos_in_byte];
- }
- } // prepare plain text
- qq_encipher((unsigned long *) plain, (unsigned long *) key, (unsigned long *) crypted); // encrypt it
- for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
- crypted[pos_in_byte] ^= plain_pre_8[pos_in_byte];
- }
- memcpy(plain_pre_8, plain, 8 ); // prepare next
- crypted_pre_8 = crypted; // store position of previous 8 byte
- crypted += 8; // prepare next output
- count += 8; // outstrlen increase by 8
- pos_in_byte = 0; // back to start
- is_header = 0; // and exit header
- } // encrypt_every_8_byte
- pos_in_byte = (instrlen + 0x0a) % 8; // header padding decided by instrlen
- if (pos_in_byte) {
- pos_in_byte = 8 - pos_in_byte;
- }
- plain[0] = (rand() & 0xf8 ) | pos_in_byte;
- memset(plain + 1, rand() & 0xff, pos_in_byte++);
- memset(plain_pre_8, 0x00, sizeof(plain_pre_8 ));
- crypted = crypted_pre_8 = outstr;
- padding = 1; // pad some stuff in header
- while (padding <= 2) { // at most two byte
- if (pos_in_byte < 8 ) {
- plain[pos_in_byte++] = rand() & 0xff;
- padding++;
- }
- if (pos_in_byte == 8 ) {
- encrypt_every_8_byte();
- }
- }
- inp = instr;
- while (instrlen > 0) {
- if (pos_in_byte < 8 ) {
- plain[pos_in_byte++] = *(inp++);
- instrlen--;
- }
- if (pos_in_byte == 8 ) {
- encrypt_every_8_byte();
- }
- }
- padding = 1; // pad some stuff in tailer
- while (padding <= 7) { // at most sever byte
- if (pos_in_byte < 8 ) {
- plain[pos_in_byte++] = 0x00;
- padding++;
- }
- if (pos_in_byte == 8) {
- encrypt_every_8_byte();
- }
- }
- *outstrlen_prt = count;
- } // qq_encrypt
- /********************************************************************
- * [decrypt part]
- * return 0 if failed, otherwise return 1
- ********************************************************************/
- int qq_decrypt(unsigned char *instr, int instrlen, unsigned char *key, unsigned char *outstr, int [color=green]*outstrlen_ptr[/color])
- {
- unsigned char decrypted[8], m[8], *crypt_buff, *crypt_buff_pre_8, *outp;
- int count, context_start, pos_in_byte, padding;
- int decrypt_every_8_byte(void) {
- for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
- if (context_start + pos_in_byte >= instrlen)
- return 1;
- decrypted[pos_in_byte] ^= crypt_buff[pos_in_byte];
- }
- qq_decipher((unsigned long *) decrypted, (unsigned long *) key, (unsigned long *) decrypted);
- context_start += 8;
- crypt_buff += 8;
- pos_in_byte = 0;
- return 1;
- } // decrypt_every_8_byte
- // at least 16 bytes and %8 == 0
- if ((instrlen % 8) || (instrlen < 16))
- return 0;
- // get information from header
- [color=red]qq_decipher((unsigned long *) instr, (unsigned long *) key, (unsigned long *) decrypted);
- [/color]
-
- pos_in_byte = decrypted[0] & 0x7;
-
- count = instrlen - pos_in_byte - 10; // this is the plaintext length
- // return if outstr buffer is not large enought or error plaintext length
- if (*outstrlen_ptr < count || count < 0)
- return 0;
- memset(m, 0, 8);
- crypt_buff_pre_8 = m;
- *outstrlen_ptr = count; // everything is ok! set return string length
- crypt_buff = instr + 8; // address of real data start
- context_start = 8; // context is at the second 8 byte
- pos_in_byte++; // start of paddng stuff
- padding = 1; // at least one in header
- while (padding <= 2) { // there are 2 byte padding stuff in header
- if (pos_in_byte < 8) { // bypass the padding stuff, none sense data
- pos_in_byte++;
- padding++;
- }
- if (pos_in_byte == 8) {
- crypt_buff_pre_8 = instr;
- if (!decrypt_every_8_byte())
- return 0;
- }
- } // while
- outp = outstr;
- while (count != 0) {
- if (pos_in_byte < 8) {
- *outp = crypt_buff_pre_8[pos_in_byte] ^ decrypted[pos_in_byte];
- outp++;
- count--;
- pos_in_byte++;
- }
- if (pos_in_byte == 8) {
- crypt_buff_pre_8 = crypt_buff - 8;
- if (!decrypt_every_8_byte())
- return 0;
- }
- } // while
- for (padding = 1; padding < 8; padding++) {
- if (pos_in_byte < 8) {
- if (crypt_buff_pre_8[pos_in_byte] ^ decrypted[pos_in_byte])
- return 0;
- pos_in_byte++;
- }
- if (pos_in_byte == 8) {
- crypt_buff_pre_8 = crypt_buff;
- if (!decrypt_every_8_byte())
- return 0;
- }
- } // for
- return 1;
- } // qq_decrypt
复制代码
gdb调试发现当调用qq_decipher函数返回时修改了outstrlen_ptr的地址,应该说outstrlen_ptr是上层函数的入参,是保存在栈中的,程序中也没有修改该地址的地方,不知那里修改了该地址?
还请高手指教
使用平台:FreeBSD 6.1 AMD64
[ 本帖最后由 free_ever 于 2007-3-25 20:32 编辑 ] |
|