觉得revering.kr上面的题目有些设计得很有意思,加上自己也需要时刻练习,于是决定来做做看。
Easy_Crack 直接拖进ida,进入DialogFunc,WM_COMMAND分支的函数,发现是明文的比较 flag: Ea5yR3versing
Easy_KeygenMe 根据ReadMe.txt,是根据Serial推Name,程序拖入ida,一个简单的算法,对username进行0~2的循环异或,以十六进制打印进buffer里,然后和Serial比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 serial = '5B134977135E7D13' ans = '' xor = [16 ,32 ,48 ] for i in range(len(serial)/2 ): tmp = serial[:2 ] tmp = int(tmp,16 ) tmp ^= xor[i%3 ] ans += chr(tmp) serial = serial[2 :] print ans
flag: K3yg3nm3
Easy_UnpackMe 这道题目,额,我觉得比较坑,原因是我不造flag要提交什么? 题目流程:首先是输入表重建,然后恢复原oep,即.text段,进入oep,然后进入winmain函数执行,winmain里就是建立一个方框,然后处理消息循环。 然而,始终不明白flag是什么,将内存dump下来,扔ida查看,也发现不了什么有用的东西。最后,flag竟然是oep,orz! flag:00401150
Music_player 程序是用vb写的,对vb不是很熟悉,但是有弹对话框,上网查vb api,对rtcmsgbox下断,向上回溯,发现EA60即60000,猜测就是1分钟的原因。改值,运行,弹出Run-time error ‘380’:Invalid property value,对RaiseException下断,然后在栈中回溯,找到程序代码,向上查看,改判断条件jge为jle,另存为文件,运行得flag。 flag: LIstenCare
vb:对vbaLenstr,vbastrcmp,vbastrcpy,rtcmsgbox下断
Replace 程序拖进ida,静态不好分析,动态调试,对GetDlgItemInt下断,由于多处call指令,导致栈上返回地址的分布不再正常,之后将运算后的值保存在eax里,对eax内存写(程序非法访问的原因)。写入的值是90,即nop,发现对401071处2个字节码改写即可输出correct(一开始注意到了E8即call,想到会不会call到输出corret的地方,但是无法和90联系。后来又看到最后的retn,想retn到输出位置,发现retun的地方是动态链接库的地址,也没法修改)。
1 2 3 4 5 6 7 8 9 10 11 #include <Windows.h> #include <stdio.h> int main () { DWORD a = 0x601605CB ; DWORD ans = 0xFFFFFFFF - a + 1 + 0x401071 ; printf ("%u\n" ,ans); system("pause" ); return 0 ; }
flag: 2687109798
ImagePrc 根据对话框显示,对MessageBox下断,向上回溯,发现LoadResource,使用Resource Hacker打开程序,发现一个文件。动态调试程序,在LoadResource后下断,发现Load的文件和资源中一致,且未发生改动,而后直接使用资源与另一地址处内容比较。再次运行程序,发现是一个绘图程序,猜测资源里的应该是标准图像。使用PIL库求解。
1 2 3 4 5 6 7 8 9 10 from PIL import Imagewidth = 200 height = 150 fp = open('resource' , 'rb' ) data = fp.read() im = Image.frombytes('RGB' , (width, height), data) im = im.transpose(Image.FLIP_TOP_BOTTOM) im.save('result.jpg' ,'jpeg' )
flag: GOT
Position 用C++写的MFC程序,程序使用CSimpleString类的GetAt方法获得对应下标的字符,用户名的前两个字符作运算以后和密码的前五个字符作比较,后两个字符作运算以后和密码的后五个字符作比较。我使用爆破的方式求解,脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 s = '76876-77776' s1,s2 = s.split('-' ,1 ) ans = '' for u1 in range(97 ,123 ): for u2 in range(97 ,123 ): for u3 in range(97 ,123 ): for u4 in range(97 ,123 ): u1_1 = (u1 & 1 ) + 5 ; u1_5 = ((u1 >> 4 ) & 1 ) + 5 ; u1_2 = ((u1 >> 1 ) & 1 ) + 5 ; u1_3 = ((u1 >> 2 ) & 1 ) + 5 ; u1_4 = ((u1 >> 3 ) & 1 ) + 5 ; u2_1 = (u2 & 1 ) + 1 ; u2_5 = ((u2 >> 4 ) & 1 ) + 1 ; u2_2 = ((u2 >> 1 ) & 1 ) + 1 ; u2_3 = ((u2 >> 2 ) & 1 ) + 1 ; u2_4 = ((u2 >> 3 ) & 1 ) + 1 ; u3_1 = (u3 & 1 ) + 5 ; u3_5 = ((u3 >> 4 ) & 1 ) + 5 ; u3_2 = ((u3 >> 1 ) & 1 ) + 5 ; u3_3 = ((u3 >> 2 ) & 1 ) + 5 ; u3_4 = ((u3 >> 3 ) & 1 ) + 5 ; u4_1 = (u4 & 1 ) + 1 ; u4_5 = ((u4 >> 4 ) & 1 ) + 1 ; u4_2 = ((u4 >> 1 ) & 1 ) + 1 ; u4_3 = ((u4 >> 2 ) & 1 ) + 1 ; u4_4 = ((u4 >> 3 ) & 1 ) + 1 ; if (u1_1 + u2_3 == ord(s1[0 ]) - ord('0' ) and u1_4 + u2_4 == ord(s1[1 ]) - ord('0' ) and u1_2 + u2_5 == ord(s1[2 ]) - ord('0' ) and u1_3 + u2_1 == ord(s1[3 ]) - ord('0' ) and u1_5 + u2_2 == ord(s1[4 ]) - ord('0' ) and u3_1 + u4_3 == ord(s2[0 ]) - ord('0' ) and u3_4 + u4_4 == ord(s2[1 ]) - ord('0' ) and u3_2 + u4_5 == ord(s2[2 ]) - ord('0' ) and u3_3 + u4_1 == ord(s2[3 ]) - ord('0' ) and u3_5 + u4_2 == ord(s2[4 ]) - ord('0' )): ans = chr(u1) + chr(u2) + chr(u3) + chr(u4) if ans[3 ] == 'p' : print ans
得到4组解:bump cqmp ftmp gpmp,一开始提交的ftmp,发现不对,但是程序是显示correct的,换bump提交成功!
flag: bump
Direct3D_FPS 一个射击游戏,用ida打开FPS.exe程序,搜索字符串,发现Game Clear!字符串,如果成功,某个地址间隔132的数组里的值要全不为1,对该数组交叉引用,发现置数组中值为0的位置,结合玩游戏的过程,猜测数组dword_409194为我们射击的对象,monster,数组dword_409190为monster_life,射击对象的生命值,每射中一次,减2的生命,将一次减2的生命改成减100(怪物生命100),每死一只怪物,程序对最后打印的加密字符串byte_407028解密一个字符。修改完程序,进行游戏,把怪物全部杀死,发现字符串并没有解密完,还差最后两个字符,应该怪物都杀死了,想不到其他点,由于是简单的异或,于是在动态调试下手解最后两个字符,得到0和m,把解密的字符串拼起来,得到flag。
flag: Thr3EDPr0m
ransomware run.exe加密了file文件,用ida打开,要解析很长时间(401000处代码不用管),直接看对文件操作的部分,程序对file文件进行了循环的密钥异或,但是程序里没有密钥,十六进制工具打开file,观察文件结尾是循环的字节,猜测文件结尾原来都是00,写脚本得解密密钥letsplaychess,运行run.exe解密文件,解密后的文件是一个可执行文件,运行得flag。
flag: Colle System
Easy ELF 确实很easy……直接拖入ida,不是明文比较就是简单异或。
flag: L1NUX
Twist1 使用单步向下的方法,od手拖外面的壳后,用ida查看,发现之后的代码是被动态加密的,还是只能用od调试。逆向过程中碰到大量的自解代码,花指令,一些变化栈的call,retn等操作,还有反调试,给我的印象就是:程序代码分散式地干扰逆向者,会比较花费逆向者的时间,password的比较倒比较简单,不过也是分散开来的,都是一些简单的异或比较,和移位比较。出题人的手法很值得学习,汇编指令是相当的熟啊!逆向过程只要使用od一直往下调,下了断点的地方,在执行以后,记得取消断点,碰到程序异常退出,就退回去找条件分支,改判断条件就行,记得改了之后还要改回来,说不定程序在哪又检测了呢?或者是改地址处的字节码呢?
flag: RIBENA
WindowKernel 使用管理员权限运行程序,开启enable按钮,往对话框输入时的处理在sys文件里,根据DeviceIoControl的第二个参数dwIoControlCode,当dwIoControlCode为0x2000时,进行check操作,在sys文件里alt + I 搜索0x2000,找到关键返回值的地方,对dword_13024交叉引用,找到了三层算法处理过程,并不复杂,每次从READ_PORT_UCHAR读一个字符,放到al里,调试的时候找到DriverEntry,然后一路跟进,在这里下断点就好,整理出一个a-z的table表,写脚本得到flag:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 index = {0x9e :'a' ,0xb0 :'b' ,0xae :'c' ,0xa0 :'d' ,0x92 :'e' ,0xa1 :'f' ,0xa2 :'g' ,0xa3 :'h' ,0x97 :'i' ,0xa4 :'j' ,0xa5 :'k' ,0xa6 :'l' ,0xb2 :'m' ,0xb1 :'n' ,0x98 :'o' ,0x99 :'p' ,0x90 :'q' ,0x93 :'r' ,0x9f :'s' ,0x94 :'t' ,0x96 :'u' ,0xaf :'v' ,0x91 :'w' ,0xad :'x' ,0x95 :'y' ,0xac :'z' } compare_table1 = [0xA5 ,0x92 ,0x95 ,0xB0 ,0xB2 ,0x85 ,0xA3 ,0x86 ,0xB4 ,0x8F ,0x8F ,0xB2 ] ans = '' for i in range(len(compare_table1)): if i > 3 and i <= 7 : compare_table1[i] ^= 0x12 elif i > 7 : compare_table1[i] ^= 0x12 compare_table1[i] ^= 0x5 for j in range(len(compare_table1)): tmp = index[compare_table1[j]] ans += tmp print ans
flag: keybdinthook
之前不会内核调试,这道题还是学会了很多的,23333!
AutoHotKey1 根据提示,需要找到两个md5值,然后解密。upx脱壳,运行出现”EXE corrupted”,搜索字符串,定位sub_4508C7这个函数,进入分析,程序取了自身的最后8个字节。验证的第一关,进行计算后的4个字节的值异或0xAAAAAAAA要与取的最后8个字节中后4个字节相同,然后以取的最后8个字节中前4个字节为偏移,从程序开头偏移前4个字节的大小,取16个字节和程序一处硬编码的值A3484BBE986C4AA9994C530A86D6487D比较。 比较成功则解密一串16进制值,得到第一串md5值:220226394582d7117410e3c021748c2a,网上解密得isolated。我们只要在程序里搜索那串比较的十六进制值,然后将其偏移填在最后8-5字节的位置,然后根据程序计算结果得到最后4字节,覆盖原来的最后4字节即可通过第一关。 再次运行,可以进行输入,使用Resource_hacker定位id为201的对话框,在ida中找到GetDlgItemText下断。 对存储字符串的buffer下读写断点,f9运行,程序自行断下,发现了一串比较的md5值:54593f6b9413fc4ff2b4dec2da337806,解密得pawn。拼起来就是flag,开始拼反了,提交了不对,orz。
flag: isolated pawn
CSHOP 额,这道题,只想用3个英文字母代替我现在所有的心情->orz!程序是一个.net程序,使用Reflector打开,对代码进行反编译,找到_Click(Object,EventArgs),发现一些字符串,运行程序,敲击回车或者空格,出来一串字符串,但是它竟然就是flag。
flag: P4W6RP6SES
PEpassword 这道题出的还是很有想法的,只是我的大脑没有转过弯来,对WM_COMMAND下断点,找到了消息处理函数,发现了esi存储着我们输入的字符串,对字符串下硬件访问断点,发现了对字符串的处理过程。程序根据我们的输入,进行了一个运算,运算结果要与一个4字节相等,jne改成je过了这个check,因为爆破基本不现实,后面两次运算,一次产生我们后面解密401000处代码用到的ebx,一次产生eax,如果输入的字符串正确,就能实现对401000处代码的正确解密,得到password。一开始想到爆破不可能,基本没有了思路,卡了很长时间。后来猜测origin.exe的开头字节可能就是解密后的字节,而加密以后的我们是知道的,二者进行简单的异或,就可以得到第一次的eax和以后正确的eax值,通过第一次正确的eax和第二次正确的eax,我们可以爆破第一次正确的ebx,从而更改寄存器的值,让401000处代码正确解密。获取第一次正确的ebx代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <stdio.h> #include <Windows.h> int main (int argc,char *argv[]) { BYTE cipher[8 ] = {0x17 ,0x2E ,0xE6 ,0xB6 ,0x05 ,0x7E ,0x0C ,0x0D }; BYTE plaintext[8 ] = {0x81 ,0xEC ,0x4C ,0x01 ,0x00 ,0x00 ,0x56 ,0x57 }; BYTE eax_byte[8 ] = {0 ,}; for (int i=0 ;i<8 ;i++) { eax_byte[i] = cipher[i] ^ plaintext[i]; } DWORD *eax_dword = (DWORD *)eax_byte; DWORD first_eax = eax_dword[0 ]; DWORD second_eax = eax_dword[1 ]; printf ("%X %X\n" ,first_eax,second_eax); DWORD eax_value = 0 ; for (int i=1 ;i<0xFFFFFFFF ;i++) { __asm { mov eax,first_eax mov ebx,i mov cl,al rol ebx,cl xor eax,ebx mov cl,bh ror eax,cl add ebx,eax mov eax_value,eax } if (eax_value == second_eax) { printf ("0x%X\n" ,i); } } system("pause" ); return 0 ; }
爆破结果有两组值,第二组0xC263A2CB正确,得到flag。
flag: From_GHL2_!!
HateIntel mach-o文件,arm架构,使用ida打开,可以反编译,搜索字符串”Input key”,简单的逻辑运算,然后作比较,脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <stdio.h> #include <Windows.h> #include <string.h> int main () { char ans[29 ] = {0 ,}; int j; BYTE compare_Byte[29 ] = {0x44 ,0xF6 ,0xF5 ,0x57 ,0xF5 ,0xC6 ,0x96 ,0xB6 ,0x56 ,0xF5 ,0x14 ,0x25 ,0xD4 ,0xF5 ,0x96 ,0xE6 ,0x37 ,0x47 ,0x27 ,0x57 ,0x36 ,0x47 ,0x96 ,0x03 ,0xE6 ,0xF3 ,0xA3 ,0x92 ,0x00 }; for (int i=0 ;i<29 ;i++) { for (int x=32 ;x<127 ;x++) { j = x; for (int q=0 ;q<4 ;q++) { j = j << 1 ; if (j & 0x100 ) { j |= 1 ; } } if ((unsigned __int8)j == compare_Byte[i]) { printf ("%d: %c\n" ,i,x); strcat (ans,(char *)&x); break ; } } } printf ("%s\n" ,ans); system("pause" ); return 0 ; }
flag: Do_u_like_ARM_instructi0n?:)
AutoHotKey2 这道题目和AutoHotkey1的思路一样,修改了pe文件之后,直接运行,出现冰与火之歌的一段描述,让你根据描述猜这个人是谁,百度一下知道是琼恩·雪诺,答案就是这个人名字的小写,去掉空格。
flag: jonsnow
SimpleVM 这道题目还是让自己涨了不少姿势,没有白忙活!23333,首先是linux下的加壳程序,让它直接运行,ida远程attach,然后dump代码段的内存,dump代码如下:
1 2 3 4 5 6 7 8 9 10 11 #include <idc.idc> static main (void ) { auto i,fp; fp = fopen("f:\\dump.dex" ,"wb" ); for (i=0x8048000 ;i<0x804C000 ;i++) { fputc(Byte(i),fp); } }
虽然以前就知道idc和python的ida脚本,但是都很少用,这次需要dump内存,Windows系统下dump内存工具很多,但是linux我就不是很熟悉了,想到用ida去dump内存,dump下来的代码段没有VM加壳,庆幸只有外层加了,23333。简单分析了一下程序,程序需要root权限,fork了子进程和父进程,利用管道进行交互,子进程得到输入的数据,然后写到管道里,父进程从管道里读数据,进行验证。 首先,我尝试去分析代码的逻辑,脑补之后发现这个200大小的数组,我实在是看不出他是什么规律,也不像是迷宫之类的东西,但是密钥长度一定小于等于7(个人脑补的结论)。想了想,想尝试爆破,把代码copy了放到vs上跑,果然跑不出来,光是跑遍5位的密码就已经吃力得不行了。果断放弃。上网搜索题解,发现了他人的思路是pintools边信道攻击,下面的笔记主要是记录一下边信道攻击。
pintools之前就接触过,但是没想过能利用到CTF上面来,自己学习pintools也就想到能直接打印内存,绕过反调试之类的,感觉用处不是很大,还不如直接用ida动调,觉得这个动态插桩工具好像没法应用到CTF上来,不过,这题着实让自己开眼了! 刚接触pintools的人都知道,pintools最简单的一个示例就是指令计数,但是思维也仅限于指令计数而已,但是边信道攻击很巧妙,恰恰利用了这个最简单的用法。如果程序的check是一个一个字符的情况,每通过一个字符或者一部分字符就能继续执行下去,那么程序执行的指令数必然会有大的增加,而pintools就可以通过执行指令数的激增来判断输入的字符是否是正确的字符,从而一个个字符地爆破,把很大数量级的爆破问题化解成为从前往后验证字符每一位的问题,而一个字符的范围不过10的平方而已。利用这个原理,写脚本进行爆破,最终得到flag。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import popen2,stringINFILE = "fx" CMD = "./pin -t source/tools/ManualExamples/obj-ia32/inscount1.so -- ./SimpleVM <" + INFILE def execlCommand (command) : fin,fout = popen2.popen2(command) result1 = fin.readline() print result1 result2 = fin.readline() print result2 fin.close() choices = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&'()*+,-./:;<=>?@[\]^_`{|}~" def writefile (data) : f = open(INFILE,'w' ) f.write(data) f.close() for entry in range(0 ,len(choices)): key = 'i' + choices[entry:entry+1 ] print ">" ,key writefile(key) execlCommand(CMD)
爆破过程如下图:
flag: id3*ndh
x64 Lotto 64位的windows程序,拖入ida简单分析,输入的6个数和随机产生的6个数比较,这里直接patch掉就好,如下图:
后面对硬编码的字符进行两次异或处理,然后自动输出结果,所以我们只需要简单patch程序,然后自动运行就可以得到flag。
flag: from_GHL2_-_!
Csharp 用dnspy打开.net程序,点击main函数里的form1()函数,功能是对MetMett方法进行解密(由于直接点击MetMett函数,显示反编译错误),需要动态执行,解密MetMett方法。在MetMetMet方法里取了我们输入的字符串,作base64encode然后进行了一次比较,比较的东西应该就在加密的方法里。使用dnspy动态调试,在解密完的地方下断,应该就能看到解密完的函数。但是我都dnspy看不到MetMetM方法的指针,没法直接找到解密以后的内存,很是尴尬,于是只有手动找解密的开头和结尾,将加密的部分抠出来,然后用脚本解密,再粘贴到MetMetM的方法上覆盖,保存文件,重新使用dnspy打开,看到比较的代码,写脚本获得flag,脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 import base64origin = '028D681E0B3FDEFFFFFF0115179B0215901F8FFFFFFF601E492D030115169B0218901F8FFFFFFF601E452D030115169B0216901F8FFFFFFF601E562D030115169B0217901F8FFFFFFF601E4C2D030115169B021E0A901F8FFFFFFF601E2B2D030115169B021D901F8FFFFFFF601FF0FFFFFF2D030115169B0219901F8FFFFFFF601E1C2D030115169B021A901F8FFFFFFF601E302D030115169B021E08901F8FFFFFFF601FE1FFFFFF2D030115169B021C901F8FFFFFFF601FEDFFFFFF2D030115169B021E09901F8FFFFFFF601FA2FFFFFF2D030115169B021B901F8FFFFFFF601E742D030115169B29' new_change = [] sum = 0 for i in range(len(origin)/2 ): tmp = origin[:2 ] tmp = int(tmp,16 ) tmp += 1 tmp &= 0xFF sum += tmp sum &= 0xFF new_change.append(tmp) origin = origin[2 :] new_change[18 ] = (sum - 38 ) & 0xFF new_change[35 ] = (sum - 3 ) & 0xFF new_change[52 ] = (sum ^ 39 ) & 0xFF new_change[69 ] = (sum - 21 ) & 0xFF new_change[87 ] = (71 - sum) & 0xFF new_change[124 ] = (sum ^ 114 ) & 0xFF new_change[141 ] = (sum ^ 80 ) & 0xFF new_change[159 ] = (235 - sum) & 0xFF new_change[179 ] = (106 + sum) & 0xFF new_change[200 ] = (36 - sum) & 0xFF new_change[220 ] = (sum - 3 ) & 0xFF for i in range(len(new_change)): if new_change[i] < 16 : print '0' + "%x" % new_change[i], else : print ("%2x" % (new_change[i])), s = '03 8e 69 1f 0c 40 df 00 00 00 02 16 18 9c 03 16 91 20 10 00 00 00 61 1f 4a 2e 04 02 16 17 9c 03 19 91 20 33 00 00 00 61 1f 46 2e 04 02 16 17 9c 03 17 91 20 11 00 00 00 61 1f 57 2e 04 02 16 17 9c 03 18 91 20 21 00 00 00 61 1f 4d 2e 04 02 16 17 9c 03 1f 0b 91 20 11 00 00 00 61 1f 2c 2e 04 02 16 17 9c 03 1e 91 20 90 00 00 00 61 20 f1 00 00 00 2e 04 02 16 17 9c 03 1a 91 20 44 00 00 00 61 1f 1d 2e 04 02 16 17 9c 03 1b 91 20 66 00 00 00 61 1f 31 2e 04 02 16 17 9c 03 1f 09 91 20 b5 00 00 00 61 20 e2 00 00 00 2e 04 02 16 17 9c 03 1d 91 20 a0 00 00 00 61 20 ee 00 00 00 2e 04 02 16 17 9c 03 1f 0a 91 20 ee 00 00 00 61 20 a3 00 00 00 2e 04 02 16 17 9c 03 1c 91 20 33 00 00 00 61 1f 75 2e 04 02 16 17 9c 2a' print '' print s.replace(' ' ,'' )ans = [] ans.append(chr(74 ^16 )) ans.append(chr(87 ^17 )) ans.append(chr(33 ^77 )) ans.append(chr(51 ^70 )) ans.append(chr(68 ^29 )) ans.append(chr(102 ^49 )) ans.append(chr(51 ^117 )) ans.append(chr(160 ^238 )) ans.append(chr(144 ^241 )) ans.append(chr(181 ^226 )) ans.append(chr(238 ^163 )) ans.append(chr(17 ^44 )) ans = '' .join(ans) print ansprint base64.b64decode(ans)
flag: dYnaaMic
Flash Encrypt flash的题目,用ffdec打开,点击scripts,然后选择其中一个打开发现是有问题的代码,Settings里勾选上Automatic deobfuscation自动反混淆,然后重新生成。此时再看scripts里的代码就很简单了,把那几个比较的数值记录下来,然后双击flashenc.swf运行,输入那些值,到达最后出现flag。
flag: 16876
Multiplicative java程序逆向,使用jad或者dj反编译程序,直接看到源代码,一个通过溢出得到值的题目。脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 from ctypes import *i = 1L while (1 ): tmp = ((2 ** 64 ) * i + 0xeaaeb43e477b8487L ) / 26729 if ((tmp * 26729 ) % (2 ** 64 )) == 0xeaaeb43e477b8487L : print c_int64(temp),i break i += 1
flag: -8978084842198767761