原文:https://www.pediy.com/kssd/pediy11/123560.html
刚来看雪论坛,就碰上腾讯的安全竞赛,恰逢盛会,怎能错过。
这段时间参加了第一阶段的比赛,四个题目,都提交了自己的答案,这里作下总结,和各位新人朋友共勉。
第一题,30多个字节
第一题是最让我心里难受的。由于是开发人员出身,找到程序的bug还是比较快的,84个字节溢出,很快找到了,但是。。。。。。就在这里卡住了。。。卡了我一个晚上,睡觉睡得都不舒服,第二个白天也是工做不安心。。。就是不知道怎么重新定向这种间接引用的指令。
call [edx]
我的思路很简单。。。就是找到一条这样的指令:
jmp [esp+xx] 或者 add esp,xx retn,xx大于等于0x28
这种指令在user32.dll里很多,但是怎么让[edx]指向这条指令。。。。搜遍内存,没找到这样的地址。。。。。就在要放弃的时候,看到那个题目下面有人说硬编码,一下子雾开云散。。。原来可以硬编码。。。。要是第一关没过,后面的估计也没有心情了。
第二题,纯编程题,擅长啊。。。花了点时间,整了个算法。
测试数据:P4 2.8G vc2008,release O2优化,算法仅需15ms,打印30ms,共45ms左右
信心大增。
第三题,keygenme,由于之前发过一遍,【第一次keygen详解,献给各位兄弟】http://bbs.pediy.com/showthread.php?t=122264,心里有数,手上不慌。但是这个比赛日期恰是周六周日,而这两天我要陪老婆。。。。不过还是花了一个通宵把注册机找出来了。
第四题,对我很难,而且周日,周一的时间,很不凑巧。基本想放弃了。昨天晚上在看雪找到了一个pespin 1.32的脱壳机,居然可以用,还提供了ollydbg脚本。不过我一开始就使用的ollydbg2.0,不支持插件,(其实我是很喜欢指令调试的,曾经的gdb,wingdb,dbx让我者迷又经常混乱。。。)所以看不懂ollydbg sript,折腾半天后在看雪上找了个教程,对着教程一条条看指令。。。不过最后还是只提交了个脱壳机脱出来的程序。。
这7-8天时间真的是够累啊,白天上班,晚上加班学习搞这些题。不过付出总会有回报,我感觉自己在安全方面慢慢入门了。呵呵呵。
另外,由于是临时会员,下载竞赛题目就花了我不少kx。哎。。。
废话少说,现在开始第三题的分析。
第三题我主要是用IDA分析,分析完后用OD验证。
keygenme的验证主流程在函数sub_4012F0()中,使用IDA逆向后c代码如下:
char __cdecl sub_4012F0() { //逆向代码有删减 v19 = (int)"ABCDEFGHJKMNPQRSTVWXYZ1234567890"; v0 = SendMessageA(hWnd, 13u, 33u, (LPARAM)lParam); v1 = v0; if ( v0 ) { v0 = SendMessageA(dword_40DBB4, 0xDu, 0x24u, (LPARAM)&v27); if ( v0 == 35 ) { v3 = 0; v2 = &v44; do { v0 = 0; while ( v3 != byte_40CF98[v0] ) // 第9,18,27个字符是‘-‘ { ++v0; if ( (unsigned int)v0 >= 3 ) goto LABEL_9; } if ( *(&v27 + byte_40CF98[v0]) != 45 ) return v0; LABEL_9: if ( v0 == 3 ) { LOBYTE(v0) = sub_407FB0(&v18, *(&v27 + v3));// 校验序列号中是否含有不在"ABCDEFGHJKMNPQRSTVWXYZ1234567890"中的字符 if ( (_BYTE)v0 == -1 ) return v0; *v2++ = *(&v27 + v3); } ++v3; } while ( v3 < 35 ); LOBYTE(v0) = sub_407E40(&v18, (int)&v44, 32, (int)&v38, (int)&v17); //对密码进行加密===>v38,长度==>v17 if ( (_BYTE)v0 ) { LOBYTE(v0) = sub_401000(v1, (int)&v20, (int)lParam); //对用户名加密 ==> v20 if ( (_BYTE)v0 ) { v4 = 20; v6 = &v20; v5 = &v38; do { if ( *(_DWORD *)v5 != *(_DWORD *)v6 ) goto LABEL_19; v4 -= 4; v6 += 4; v5 += 4; } while ( (unsigned int)v4 >= 4 ); if ( v4 ) { LABEL_19: v7 = (unsigned __int8)*v5 - (unsigned __int8)*v6; if ( (unsigned __int8)*v5 != (unsigned __int8)*v6 || (v8 = v4 - 1, v10 = (int)(v6 + 1), v9 = (int)(v5 + 1), v8) && ((v7 = *(_BYTE *)v9 - *(_BYTE *)v10, *(_BYTE *)v9 != *(_BYTE *)v10) || (v11 = v8 - 1, v13 = v10 + 1, v12 = v9 + 1, v11) && ((v7 = *(_BYTE *)v12 - *(_BYTE *)v13, *(_BYTE *)v12 != *(_BYTE *)v13) || (v15 = v13 + 1, v14 = v12 + 1, v11 != 1) && (v7 = *(_BYTE *)v14 - *(_BYTE *)v15, *(_BYTE *)v14 != *(_BYTE *)v15))) ) { v0 = 1; if ( v7 <= 0 ) v0 = -1; LABEL_29: if ( !v0 ) LOBYTE(v0) = MessageBoxA( dword_40DBB8, "Congratulations! \n You will be the keygen machine!", "Success!", 0); return v0; } } v0 = 0; goto LABEL_29; } } } } return v0; }
char __usercall sub_401000<al>(int a1<ecx>, int a2<edi>, int a3) { //逆向代码有删减 v3 = a1; v17 = 0; memset(&v18, 0, 0x2Bu); v12 = dword_40AB90; v13 = dword_40AB94; VolumeSerialNumber = 0; v11 = 0; v10 = 0; v14 = dword_40AB98; v15 = dword_40AB9C; v16 = dword_40ABA0; if ( a2 && a3 ) { GetVolumeInformationA("C:\\", 0, 0, &VolumeSerialNumber, 0, 0, 0, 0); //获取卷标 sub_407950(&v17, a3, v3); v5 = BYTE1(VolumeSerialNumber); v6 = BYTE2(VolumeSerialNumber); *(&v17 + v3) = VolumeSerialNumber; //把卷标加到username后 v7 = BYTE3(VolumeSerialNumber); *(&v18 + v3) = v5; *(&v19 + v3) = v6; *(&v20 + v3) = v7; v8 = sub_4078E0("Tencent"); sub_407950(&v21[v3], "Tencent", v8); sub_407C40(&v10, (int)&v17, v3 + 11); //把Tencent字符串加到卷标后 sub_407D00(&v10, a2); //使用变形的sha1对username+c盘卷号+"Tencent"散列。 result = 1; } else { result = 0; } return result; }
DWORD const_value_1 = 0xB1CAB1CA; DWORD const_value_2 = 0xCCBFCCBF; DWORD const_value_3 = 0xBFB2D6BE; DWORD const_value_4 = 0xF8C7D8B5; DWORD const_value_5 = 0xEEC7BCCD;
char __thiscall sub_407E40(void *this, int a2, int a3, int a4, int a5) { int v5; // ebx@1 int v6; // esi@1 int v7; // eax@5 char result; // al@6 int v9; // eax@9 int v10; // eax@12 int v11; // edx@13 int v12; // ebp@17 unsigned __int8 v13; // al@18 void *v14; // [sp+10h] [bp-4h]@1 v5 = 0; v6 = 0; v14 = this; if ( !a2 || !a5 || a3 <= 0 ) return 0; if ( a4 ) { if ( *(_DWORD *)a5 <= 0 ) return 0; sub_407DF0(this); v9 = 0; if ( a3 > 0 ) { while ( *((_BYTE *)v14 + *(_BYTE *)(v9 + a2)) != -1 ) { ++v9; if ( v9 >= a3 ) goto LABEL_12; } return 0; } LABEL_12: v10 = sub_407980(a2, byte_40CE68, a3); if ( v10 ) { v11 = v10 - a2; a3 = v10 - a2; } else { v11 = a3; } if ( *(_DWORD *)a5 < (5 * v11 >> 3) + 1 ) return 0; v12 = 0; if ( v11 <= 0 ) { LABEL_24: *(_DWORD *)a5 = v6; return 1; } while ( 1 ) { v13 = *((_BYTE *)v14 + *(_BYTE *)(a2 + v12)); if ( (unsigned int)v5 > 3 ) break; v5 = (v5 - 3) & 7; if ( v5 ) goto LABEL_22; *(_BYTE *)(v6++ + a4) |= v13; LABEL_23: ++v12; if ( v12 >= v11 ) goto LABEL_24; } v5 = (v5 - 3) & 7; *(_BYTE *)(v6 + a4) |= v13 >> v5; v11 = a3; ++v6; LABEL_22: *(_BYTE *)(v6 + a4) |= v13 << (8 - v5); goto LABEL_23; } v7 = sub_407980(a2, byte_40CE68, a3); if ( v7 ) { *(_DWORD *)a5 = (5 * (v7 - a2) >> 3) + 1; result = 1; } else { *(_DWORD *)a5 = (5 * a3 >> 3) + 1; result = 1; } return result; }
char* find_ch(char* str, char tofind, int len) { if(len <=0) return 0; while(*str != tofind) { --len; ++str; if(len<=0) break; } return str; } void sha1_serial(char* serial, int len) { BYTE buf[0x100]; DWORD value=0x15; memset(encrypt_serial,0,sizeof(encrypt_serial)); memset(buf,255,0x100); for(int i=0;i<32;++i) { *(buf+const_str_2[i])=i; } *(buf+const_char)=32; int len1=0; char* pos1 = find_ch(serial,const_char,len); if(pos1) { len1=pos1-serial; len = pos1-serial; } else { len1=len; } if(value < ((5*len1)>>3)+1 || len1<=0)//如果第一个字母是'=',则退出 { return; } int index=0; int index_encrypt=0; int ctrl=0; char c = 0; while(1) { c = *(buf+serial[index]); if(ctrl > 3) { ctrl = (ctrl-3) & 7; encrypt_serial[index_encrypt++]|= c>>ctrl; encrypt_serial[index_encrypt] |= c<<(8-ctrl); } else { ctrl = (ctrl-3) & 7; if(ctrl) { encrypt_serial[index_encrypt] |= c<<(8-ctrl); } else { encrypt_serial[index_encrypt++] |= c; } } ++index; if(index>=len1) { value = index_encrypt; return; } } char* pos2 = find_ch(serial,const_char,len); if ( pos2 ) { value = (5 * (pos2 - serial) >> 3) + 1; } else { value = (5 * len >> 3) + 1; } }
//sha1算法代码摘自网络 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <errno.h> #include <Windows.h> /**************************************************************** * a0 a0 a0 a0 a0 a1 a1 a1 | a1 a1 a2 a2 a2 a2 a2 a3 | a3 a3 a3 a3 a4 a4 a4 a4 | a4 a5 a5 a5 a5 a5 a6 a6 | a6 a6 a6 a7 a7 a7 a7 a7 *****************************************************************/ typedef unsigned char BYTE; typedef unsigned int u32; typedef struct { u32 h0,h1,h2,h3,h4; u32 nblocks; unsigned char buf[64]; int count; } SHA1_CONTEXT; void sha1_init( SHA1_CONTEXT *hd ); void sha1_write( SHA1_CONTEXT *hd, unsigned char *inbuf, size_t inlen); void sha1_final(SHA1_CONTEXT *hd); BYTE encrypt_username[20]; char keygenme_serial[40]; char* const_str_1 = "Tencent"; char* const_str_2 = "ABCDEFGHJKMNPQRSTVWXYZ1234567890"; char const_char = '='; DWORD const_value_1 = 0xB1CAB1CA; DWORD const_value_2 = 0xCCBFCCBF; DWORD const_value_3 = 0xBFB2D6BE; DWORD const_value_4 = 0xF8C7D8B5; DWORD const_value_5 = 0xEEC7BCCD; void sha1_username(char* username, int len) { BYTE content[44]; memset(content,0,sizeof(content)); DWORD volumeSerialNumber; GetVolumeInformationA("C:\\", 0, 0, &volumeSerialNumber, 0, 0, 0, 0); memcpy(content,username,len); memcpy(content+len,&volumeSerialNumber,4); memcpy(content+len+4,const_str_1,strlen(const_str_1)+1); int content_len = len + strlen(const_str_1) + 4; SHA1_CONTEXT ctx; sha1_init (&ctx); sha1_write (&ctx, content, content_len); sha1_final (&ctx); memcpy(encrypt_username,ctx.buf,20); } void sha1_username_to_serial() { BYTE encrypt_serial[32]; int j=0; for(int i=0;i<20; i=i+5) { BYTE b0 = encrypt_username[i]; BYTE b1 = encrypt_username[i+1]; BYTE b2 = encrypt_username[i+2]; BYTE b3 = encrypt_username[i+3]; BYTE b4 = encrypt_username[i+4]; encrypt_serial[j]=b0>>3; encrypt_serial[j+1]=((b0<<2)&0x1f)|(b1>>6); encrypt_serial[j+2]=(b1>>1)&0x1f; encrypt_serial[j+3]=((b1<<4)&0x1f) | (b2>>4); encrypt_serial[j+4]=((b2<<1)&0x1f)| (b3>>7); encrypt_serial[j+5]=(b3>>2)&0x1f; encrypt_serial[j+6]=((b3<<3)&0x1f)|(b4>>5); encrypt_serial[j+7]=b4&0x1f; j=j+8; } int n=0; for(int k=0;k<32;++k) { if(n==8 || n==17 || n==26) { keygenme_serial[n++] = '-'; } keygenme_serial[n++]=const_str_2[encrypt_serial[k]]; } } int main(int argc, char** argv) { if(argc <= 1) { printf("please input User Name!\n"); return 1; } if(strlen(argv[1])>32) { printf("User name is too long!\n"); return 1; } char* username = argv[1]; sha1_username(username,strlen(username)); sha1_username_to_serial(); printf("User Name=%s\n",username); printf("License Code=%s\n",keygenme_serial); return 0; } //**************sha1 代码************************ /* SHA-1 coden take from gnupg 1.3.92. */ // sha-1代码省略