本帖最后由 一筐萝卜 于 2018-11-19 19:10 编辑
CPP
- 题目是一个64位ELF文件
- 拖入IDA中f5查看main函数伪代码
[Asm] 纯文本查看 复制代码 __int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
char v4; // [rsp+0h] [rbp-80h]
char v5; // [rsp+20h] [rbp-60h]
char v6; // [rsp+40h] [rbp-40h]
unsigned __int64 v7; // [rsp+68h] [rbp-18h]
v7 = __readfsqword(0x28u);
std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::basic_string(&v4, a2, a3);
std ::operator<<< std ::char_traits<char>>(& std ::cout, "input flag:" );
std ::operator>><char, std ::char_traits<char>, std ::allocator<char>>(& std ::cin, &v4);
std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::basic_string(&v6, &v4);
sub_4010A2((__int64)&v5, (__int64)&v6, (__int64)&v6);
std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::~basic_string(&v6);
sub_401332((__int64)&v5);
sub_40154E((__int64)&v5);
std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::~basic_string(&v4);
return 0LL;
}
|
- 通过伪代码可以看出来,这是一个用C++写的
- 这么长一串其实是引用了C++的字符串类,当时我也是没有看懂,也是第一次遇到
[Asm] 纯文本查看 复制代码 std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::basic_string
|
- 通过引用字符串"input flag:"我们可以推断出“std::operator<<<std::char_traits<char>>(&std::cout, "input flag:");”是输出字符串的意思,而std::operator>><char,std::char_traits<char>,std::allocator<char>>(&std::cin, &v4)是输入字符串的意思
- 通过动态调试可以发现std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v6, &v4);这个函数是将v4的值复制到v6
- 然后进入sub_4010A2,通过看汇编代码可以发现,这个函数其实是传入两个参数“sub_4010A2(&v5,&v6)”
[Asm] 纯文本查看 复制代码 1 2 3 4 5 6 | void __fastcall sub_4010A2(__int64 a1, __int64 a2, __int64 a3){
std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::basic_string(a1, a2, a3);
std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::operator=(a1, a2);// 把a2的值复制到a1
sub_40111A(a1);
sub_40110E();
}
|
- 在函数里面首先是将a2的值传入a1中,也就是将v6的值传入v5
- 然后进入sub_40111A()
[Asm] 纯文本查看 复制代码 unsigned __int64 __fastcall sub_40111A(__int64 a1)
{
_BYTE *v1; // rbx
int v2; // er12
const char *v3; // rax
int i; // [rsp+1Ch] [rbp-54h]
char s1; // [rsp+20h] [rbp-50h]
char v7; // [rsp+21h] [rbp-4Fh]
char v8; // [rsp+22h] [rbp-4Eh]
char v9; // [rsp+23h] [rbp-4Dh]
char v10; // [rsp+24h] [rbp-4Ch]
char v11; // [rsp+25h] [rbp-4Bh]
char v12; // [rsp+26h] [rbp-4Ah]
char v13; // [rsp+27h] [rbp-49h]
char v14; // [rsp+28h] [rbp-48h]
char v15; // [rsp+29h] [rbp-47h]
char v16; // [rsp+2Ah] [rbp-46h]
char v17; // [rsp+2Bh] [rbp-45h]
char v18; // [rsp+2Ch] [rbp-44h]
char v19; // [rsp+2Dh] [rbp-43h]
char v20; // [rsp+2Eh] [rbp-42h]
char v21; // [rsp+2Fh] [rbp-41h]
char v22; // [rsp+30h] [rbp-40h]
char v23; // [rsp+31h] [rbp-3Fh]
char v24; // [rsp+32h] [rbp-3Eh]
char v25; // [rsp+33h] [rbp-3Dh]
char v26; // [rsp+34h] [rbp-3Ch]
char v27; // [rsp+35h] [rbp-3Bh]
char v28; // [rsp+36h] [rbp-3Ah]
char v29; // [rsp+37h] [rbp-39h]
char v30; // [rsp+38h] [rbp-38h]
char v31; // [rsp+39h] [rbp-37h]
char v32; // [rsp+3Ah] [rbp-36h]
char v33; // [rsp+3Bh] [rbp-35h]
char v34; // [rsp+3Ch] [rbp-34h]
char v35; // [rsp+3Dh] [rbp-33h]
char v36; // [rsp+3Eh] [rbp-32h]
char v37; // [rsp+3Fh] [rbp-31h]
char v38; // [rsp+40h] [rbp-30h]
char v39; // [rsp+41h] [rbp-2Fh]
char v40; // [rsp+42h] [rbp-2Eh]
char v41; // [rsp+43h] [rbp-2Dh]
char v42; // [rsp+44h] [rbp-2Ch]
char v43; // [rsp+45h] [rbp-2Bh]
char v44; // [rsp+46h] [rbp-2Ah]
char v45; // [rsp+47h] [rbp-29h]
char v46; // [rsp+48h] [rbp-28h]
char v47; // [rsp+49h] [rbp-27h]
char v48; // [rsp+4Ah] [rbp-26h]
unsigned __int64 v49; // [rsp+58h] [rbp-18h]
v49 = __readfsqword(0x28u);
s1 = 0x99u;
v7 = 0xB0u;
v8 = 0x87u;
v9 = 0x9Eu;
v10 = 0x84u;
v11 = 0xA0u;
v12 = 0xCBu;
v13 = 0xEFu;
v14 = 0x88u;
v15 = 0x90u;
v16 = 0xBBu;
v17 = 0x8Eu;
v18 = 0x91u;
v19 = 0xE0u;
v20 = 0xD2u;
v21 = 0xAEu;
v22 = 0xD4u;
v23 = 0xC5u;
v24 = 0x6F;
v25 = 0xD7u;
v26 = 0xC0u;
v27 = 0x68;
v28 = 0xC6u;
v29 = 0x6A;
v30 = 0x81u;
v31 = 0xC9u;
v32 = 0xB7u;
v33 = 0xD7u;
v34 = 0x61;
v35 = 4;
v36 = 0xDAu;
v37 = 0xCFu;
v38 = 0x3D;
v39 = 0x5C;
v40 = 0xD6u;
v41 = 0xEFu;
v42 = 0xD0u;
v43 = 0x58;
v44 = 0xEFu;
v45 = 0xF2u;
v46 = 0xADu;
v47 = 0xADu;
v48 = 0xDFu;
for ( i = 0;
i < (unsigned __int64) std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>:: length (a1);
++i )
{
v1 = (_BYTE *) std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::operator[](a1, i);// a1[i]
v2 = 4 * *(char *) std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::operator[](a1, i);
*v1 = ((*(_BYTE *) std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::operator[](a1, i) >> 6) | v2) ^ i;
}
v3 = (const char *) std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::c_str(a1);
if ( strcmp(&s1, v3) == 0 )
{
sub_4012CE(a1);
exit(0);
}
return __readfsqword(0x28u) ^ v49;
}
|
- 然后经过调试发现std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator[]的意思是取我们输入的第i个值,即a1
[Asm] 纯文本查看 复制代码 .text:0000000000401234 movzx eax , byte ptr [rax]
.text:0000000000401237 movsx eax , al
.text:000000000040123A shl eax , 2
|
- 首先是先将a1[\i]进行左移两位
- 然后将a1的值算术右移6,然后与v2进行或运算,即与“a<<2”进行或运算,随后与i的值进行异或
- 这一轮下来,总结一下这个循环干了什么:a=(a<<2|a>>6)^i,该循环将a1的每一位都进行这样的操作
- 当循环结束后,与s1进行比较,所以我们要把s1的数据提取出来,然后根据刚刚的运算进行反推,脚本如下:
[Python] 纯文本查看 复制代码 s1 = [ 0x99 , 0xB0 , 0x87 , 0x9E , 0x84 , 0xA0 , 0xCB , 0xEF , 0x88 , 0x90 , 0xBB , 0x8E , 0x91 , 0xE0 , 0xD2 , 0xAE , 0xD4 , 0xC5 , 0x6F , 0xD7 , 0xC0 , 0x68 , 0xC6 , 0x6A , 0x81 , 0xC9 , 0xB7 , 0xD7 , 0x61 , 4 , 0xDA , 0xCF , 0x3D , 0x5C , 0xD6 , 0xEF , 0xD0 , 0x58 , 0xEF , 0xF2 , 0xAD , 0xAD , 0xDF ]
flag = ""
for x in range ( 0 , len (s1)):
for asc in range ( 32 , 128 ):
if (asc>> 6 |asc<< 2 )& 0xff = = s1[x]^x:
flag + = chr (asc)
break
print flag
|
- 我在写脚本的时候也遇到一个错误,就是我之前没遇到过,最开始我的脚本是这样的,“(asc>>6|asc<<2)==s1[x]^x”,然后死活也跑不出来东西,经过查阅之后发现还需要加一个&0xff的操作
- 该脚本跑出来的是“flag is: flag{7h15_15_4_f4k3_F14G_=3=_rua!}”
- 当比较成功之后会进入sub_4012CE()函数里面,这个函数的作用就是输出两句话:“good job,but .....”,很显然,题目并没有这个简单,接着往下面分析
- std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string,该函数应该是把刚刚分配的变量v6给撤销掉,然后进入sub_401332
[Asm] 纯文本查看 复制代码 unsigned __int64 __fastcall sub_401332(__int64 a1)
{
_BYTE *v1; // r12
int v2; // ebx
char v3; // r13
const char *v4; // rax
signed int i; // [rsp+18h] [rbp-58h]
signed int j; // [rsp+1Ch] [rbp-54h]
char s[8]; // [rsp+20h] [rbp-50h]
__int64 v9; // [rsp+28h] [rbp-48h]
__int64 v10; // [rsp+30h] [rbp-40h]
__int64 v11; // [rsp+38h] [rbp-38h]
char v12; // [rsp+40h] [rbp-30h]
unsigned __int64 v13; // [rsp+48h] [rbp-28h]
v13 = __readfsqword(0x28u);
v12 = 0;
s[0] = -103;
s[1] = -80;
s[2] = -121;
s[3] = -98;
s[4] = 112;
s[5] = -24;
s[6] = 65;
s[7] = 68;
v9 = 0x5855BC749A8B0405LL;
v10 = -1920493130842480203LL;
v11 = -3031743088776258207LL;
for ( i = 0; i <= 3; ++i )
{
for ( j = 1; j < strlen(s); ++j )
{
v1 = (_BYTE *) std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::operator[](a1, j);
v2 = *(unsigned __int8 *) std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::operator[](
a1,
j);
v3 = *(_BYTE *) std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::operator[](a1, j - 1) | v2;
LOBYTE(v2) = *(_BYTE *) std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::operator[](
a1,
j);
*v1 = v3 & ~(v2 & *(_BYTE *) std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::operator[](
a1,
j - 1));
}
}
v4 = (const char *) std ::__cxx11::basic_string<char, std ::char_traits<char>, std ::allocator<char>>::c_str(a1);
if ( strncmp(v4, s, 32uLL) == 0 )
sub_401522();
return __readfsqword(0x28u) ^ v13;
}
|
- 进入函数之后,先进行一系列的赋值操作,然后是一个大循环,循环次数为4次,在这个大循环中套着一个小循环,小循环的次数是我们字符串s的长度,经过在上一个check函数跳过的坑,所以我们对这一个check函数直接看汇编代码
- 程序先将a[j]取出来,再将a[j-1]|a[j],当我调试的时候发现第一次或运算的两个数是0xc0和0xc5,这个我就很是纳闷了,我之前输入的是012345....,怎么变成了0xc0、0xc5了呢,然后回头一想,我们的字符串在之前的check函数进行过一次处理
[Python] 纯文本查看 复制代码 str1 = "0123456789abcdef"
i = 0
for x in str1:
print hex ((( ord (x)<< 2 )|( ord (x)>> 6 ))& 0xff ^i),
i + = 1
out: 0xc0 0xc5 0xca 0xcf 0xd4 0xd1 0xde 0xdb 0xe8 0xed 0x8f 0x82 0x81 0x9c 0x9b 0x96
|
- emmmmmmm,这就对上了,第一次“0xc5|0xc0=0xc5”,然后将计算的结果和a[j-1]进行&运算"0xc5 & 0xc0 = 0xc0 ",然后再将结果进去not(按位取反)“~0xc0”,然后和a[j]进行and操作,最后得到的结果为5,综上所述,这个多的运算其实是将a[j]=a[j]^a[j-1],验证一下:
- 和刚刚的到的结果吻合,所以我们的推测是对的,根据刚刚的调试简化sub_401332这个函数
[Python] 纯文本查看 复制代码 for i in range ( 4 ):
for j in range ( 32 ):
a[j] = a[j]^a[j - 1 ]
|
- 当循环结束后,把处理过的字符串和s进行比较,如果正确的话,就会输出“you got it!”,看来这才是真正的flag,脚本如下:
[Python] 纯文本查看 复制代码 list1 = [ 0x99 , 0xB0 , 0x87 , 0x9E , 0x70 , 0xE8 , 0x41 , 0x44 , 5 , 4 , 0x8B , 0x9A , 0x74 , 0xBC , 0x55 , 0x58 , 0xB5 , 0x61 , 0x8E , 0x36 , 0xAC , 9 , 0x59 , 0xE5 , 0x61 , 0xDD , 0x3E , 0x3F , 0xB9 , 0x15 , 0xED , 0xD5 ]
for x in range ( 4 ):
for x in range ( 31 , 0 , - 1 ):
list1[x] = list1[x]^list1[x - 1 ]
flag = ""
for x in range ( len (list1)):
flag + = chr (((list1[x]^x)<< 6 |(list1[x]^x)>> 2 )& 0xff )
print flag
|
- 写这个脚本的时候我还是有点迷,迷在他们之间的关系,check2异或运算是从第2个开始的加密
[Asm] 纯文本查看 复制代码 加密:
a[0]= 4 a[1] = 5 a[2] = 6
a[1] = a[1]^a[0] = 5^4 = 1
a[2] = a[2]^a[1] = 6^1 = 7
解密:
a[2] = a[2]^a[1] = 7^1 = 6
a[1] = a[1]^a[0] = 1^4 = 5
|
What’s_it
- 该题目为32位PE文件,使用PEID检测发现没有加壳
- 拖入IDA中,查看main函数
[Asm] 纯文本查看 复制代码 int __cdecl main( int argc, const char **argv, const char **envp)
{
unsigned __int8 v4[4]; // [ esp +1Ch] [ ebp -48h]
unsigned __int8 v5[4]; // [ esp +20h] [ ebp -44h]
char v6[32]; // [ esp +24h] [ ebp -40h]
char v7; // [ esp +44h] [ ebp -20h]
char Str [4]; // [ esp +45h] [ ebp -1Fh]
__int16 v9; // [ esp +49h] [ ebp -1Bh]
char v10; // [ esp +4Bh] [ ebp -19h]
int k; // [ esp +4Ch] [ ebp -18h]
int j; // [ esp +50h] [ ebp -14h]
int i; // [ esp +54h] [ ebp -10h]
int v14; // [ esp +58h] [ ebp - Ch ]
int v15; // [ esp +5Ch] [ ebp -8h]
__main();
*(_DWORD *) Str = 0;
v9 = 0;
v10 = 0;
memset(v6, 0, sizeof (v6));
v7 = 0;
*(_DWORD *)v5 = 0;
*(_DWORD *)v4 = 0;
v15 = 0;
v14 = 0;
printf( "Please input your luck string:" );
scanf( "%s" , Str );
if ( strlen( Str ) != 6 )
return 0;
for ( i = 0; i <= 5; ++i )
{
if ( Str [i] <= '`' || Str [i] > 'z' ) // 限制string全部为小写
return 0;
}
getMD5( Str , v6); // v6是加密后的ozulmt
for ( j = 0; j <= 31; ++j )
{
if ( v6[j] == '0' )
{
++v15;
v14 += j;
}
}
if ( 10 * v15 + v14 == 403 )
{
for ( k = 0; k <= 3; ++k )
{
v5[k] = v6[k]; // v5是md5的前四位
v4[k] = v6[k + 28]; // v4是md5的后四位
}
decode(v4);
}
check(v5);
return 0;
}
|
- 该程序首先让你输入一个luck string,规定长度为6,必须全部是小写字母,并且md5加密后,0的个数和所在的下标满足“ 10 * 个数 + 下标和 == 403”
- 接下来就是用python写脚本进行爆破
[Python] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | false[ / color]]
import hashlib
def md5encode(str1):
a = hashlib.md5()
a.update(str1)
return a.hexdigest()
def seek_luckstring():
string = ""
for a in range ( 97 , 123 ):
for b in range ( 97 , 123 ):
for c in range ( 97 , 123 ):
for d in range ( 97 , 123 ):
for e in range ( 97 , 123 ):
for f in range ( 97 , 123 ):
string = chr (a) + chr (b) + chr (c) + chr (d) + chr (e) + chr (f)
md5_string = md5encode(string)
v14 = 0
v15 = 0
for x in range ( len (md5_string)):
if md5_string[x] = = "0" :
v15 + = 1
v14 + = x
if 10 * v15 + v14 = = 403 :
print string
exit( 0 )
seek_luckstring()
|
- 最后得出luckstring是“ozulmt”
- 然后通过循环分别给v4,v5赋值def seek_v4v5():
[Python] 纯文本查看 复制代码 def seek_v4v5():
luckstring = md5encode( "ozulmt" )
print luckstring
v4 = [""] * 4
v5 = [""] * 4
for x in range ( 4 ):
v5[x] = luckstring[x]
v4[x] = luckstring[x + 28 ]
print v4
print v5
|
[Asm] 纯文本查看 复制代码 // write access to const memory has been detected, the output may be wrong!
signed int __cdecl decode(unsigned __int8 *a1)
{
signed int result; // eax
signed int j; // [ esp +24h] [ ebp -14h]
signed int i; // [ esp +28h] [ ebp -10h]
unsigned int Seed; // [ esp +2Ch] [ ebp - Ch ]
Seed = 0;
for ( i = 0; i <= 3; ++i )
Seed += a1[i]; // seed = 246
srand(Seed);
*(_BYTE *)check ^= 0x96u; // check = 0xc3
for ( j = 1;
{
result = j;
if ( j >= 305 )
break;
*((_BYTE *)check + j) ^= rand();
}
return result;
}
|
- 这个函数是对check函数的字节码进行操作,将数组v4中的每一个值得ASCII码加起来作为srand的种子,然后将check的每一个字节码都与rand()产生的随机数进行异或
- 我们知道,当srand()的种子一样的情况下,生成的rand()随机值也是一样的,所以check函数是可以恢复的
- 我动态调试的时候,check函数确实恢复成功了
- 通过观察,我们可以知道这个函数首先让你输入一个flag,然后进入到checkht函数中
[Asm] 纯文本查看 复制代码 char *__cdecl checkht(char *Dest)
{
int v1; // eax
char Source[48]; // [ esp +1Ch] [ ebp -4Ch]
__int16 v4; // [ esp +4Ch] [ ebp -1Ch]
int v5; // [ esp +4Eh] [ ebp -1Ah]
__int16 v6; // [ esp +52h] [ ebp -16h]
int j; // [ esp +54h] [ ebp -14h]
int i; // [ esp +58h] [ ebp -10h]
int v9; // [ esp +5Ch] [ ebp - Ch ]
v5 = 1734437990;
v6 = 123;
memset(Source, 0, sizeof (Source));
v4 = 0;
v9 = 5;
for ( i = 0;
{
v1 = strlens(Dest);
if ( v1 - 1 <= v9 )
break;
if ( Dest[v9] == '-' ) // 去掉我们输入字符串中的 "-" ,新字符串存在source中
--i;
else
Source[i] = Dest[v9];
++v9;
}
for ( j = 0; j <= 4; ++j )
{
if ( Dest[j] != *((_BYTE *)&v5 + j) ) // 前5位位 "flag{"
{
printfs(0);
exit(0);
}
}
if ( Dest[13] != Dest[28] ) // Dest[13] == Dest[28]
{
printfs(0);
exit(0);
}
if ( Dest[13] != Dest[18] )
{
printfs(0);
exit(0);
}
if ( Dest[13] != Dest[23] )
{
printfs(0);
exit(0);
}
if ( Dest[13] != 45 )
{
printfs(0);
exit(0);
}
if ( Dest[41] != '}' )
{
printfs(0);
exit(0);
}
return strcpy(Dest, Source);
}
|
- 该函数首先把我们输入的字符串进行去除“-”,然后有几个判断,如果有一个不满足则会退出程序:
[Asm] 纯文本查看 复制代码 条件:
前5位位 "flag{"
Dest[13] == Dest[28] = "-"
Dest[13] == Dest[18] = "-"
Dest[13] == Dest[23] = "-"
Dest[13] == 45 = "-"
最后一个为 '}'
|
- 最后将处理后的字符串返回,接着看check函数,又是利用随机值来生成一个正确的flag,饭后与我们的输入进行比较
[Python] 纯文本查看 复制代码 def check2():
ASCII = "0123456789abcdef"
rand = [ 1018 , 20977 , 6537 , 12471 , 23035 , 10168 , 24596 , 6071 , 15959 , 21200 , 27017 , 8546 , 23669 , 16211 , 26282 , 7236 , 26183 , 16060 , 27924 , 26961 , 4987 , 23116 , 4119 , 365 , 8438 , 9389 , 31685 , 29746 , 25726 , 20182 , 17993 , 17389 ]
flag = ""
for x in range ( len (rand)):
flag + = ASCII[rand[x] % 16 ]
print flag
|
- 我们可以得到一串字符串a197b847709253a47c41bc7d6d52e69d,然后根据之前的那几个限制条件,得出最终的flag:flag{a197b847-7092-53a4-7c41-bc7d6d52e69d}
[Asm] 纯文本查看 复制代码 def check2():
# v5 = [ '0' , 'e' , 'c' , '4' ]
# v10 = 0
# for x in range(len(v5)):
# v10 += ord(v5[x])
# print v10
# v10 = 300
ASCII = "0123456789abcdef"
rand = [1018,20977,6537,12471,23035,10168,24596,6071,15959,21200,27017,8546,23669,16211,26282,7236,26183,16060,27924,26961,4987,23116,4119,365,8438,9389,31685,29746,25726,20182,17993,17389]
flag = ""
for x in range(len(rand)):
flag+=ASCII[rand[x]%16]
print flag
#a197b847709253a47c41bc7d6d52e69d
|
cyvm
- 同样拖入IDA中查看伪C代码,发现是循环里套switch,代码非常多,我还以为是算法题,然后我分析了好长时间没分析出来,根据官方WP,这道题是一个VM题
- WP上有一句话值得我记住,就是“while循环套switch,不是迷宫就是vm”,这也许就是经验只谈吧,我这个没经验的人看起来这个题是算法题emmmmmmm
- 判断是VM:1.看到这么多case,那一定是vm了 2.根据传入函数的a2和每次goto前的”+=”运算可以很容易的确定v5是读字节码的操作
- 根据WP分析出:
[Python] 纯文本查看 复制代码 s2reg 1
reg2s 2
mov 3
add 4
sub 5
xor 6
and 7
jmp 9
cmp 10
or 11
jnz 12
putc 13
ipt 15
movs 16
adds 17
inc 18
|
[Python] 纯文本查看 复制代码 s1 = [ 0x0A , 0x0C , 4 , 0x1F , 0x48 , 0x5A , 0x5F , 3 , 0x62 , 0x67 , 0x0E , 0x61 , 0x1E , 0x19 , 8 , 0x36 , 0x47 , 0x52 , 0x13 , 0x57 , 0x7C , 0x39 , 0x54 , 0x4B , 5 , 5 , 0x45 , 0x77 , 0x15 , 0x26 , 0x0E , 0x62 , 0 ]
for x in range ( 31 , - 1 , - 1 ):
s1[x] ^ = s1[x + 1 ]^x
flag = ""
for x in range ( len (s1)):
flag + = chr (s1[x])
print flag
|
|