BugkuCTF ConsoleApplication4解题思路及相关知识点

  • 这个题的意思是:
         一共8栈灯,每盏灯的状态改变都会改变它前后挨着的两个灯的状态,要求点亮所有的灯获得flag
         要求输入数的范围在1-8之间,0是重新开始

思路一:

  • 一:         

     算法是1-8,8栈灯,点一个改变3状态,写脚本爆破吧!!(想模仿出题人的想法把中间过程表达出来,结果还是自己太年            轻)
     
     贪心
     一个灯如果按了第二下,就会抵消上一次按下所产生的影响。 
     因此,一个灯只有按或者不按两种情况,不存在一个灯要开关多次的情况。 
     例如八个灯 00000000 
     按1后 11000000 
     按3后 10110000 
     按1后 01110000 
     这和八个灯 00000000 
     只按一次3后 01110000 
     是完全相同的情况
     #####但是后来我忽略了一个因素:我们这里最后一个灯会影响第一个灯,它是个环,放在这不行

lamp = [0, 0, 0, 0, 0, 0, 0, 0]
a = []
status = True
for i in range(1, 6, 1):
    if lamp[i-1] == 0:
        lamp[i-1] ^= 1
        lamp[i] ^= 1
        lamp[i+1] ^= 1
if lamp[7] == 0:
    lamp[7] = 1
    lamp[0] ^= 1
    lamp[1] ^= 1
print(lamp)
lamp[7] = 1
lamp[0] = 1
lamp[1] = 1
   # 我想多了

上面的脚本压根不是那个情况,回头去od动态调试

思路二:

毕竟是逆向,后来进入od再次寻找解决方案:

    搜索到字符串done the flag is找到汇编代码处:
    00FDE968  done the flag is
    这个地址的头是FDE940  
    跳转来自00FD7AB4
    
    直接在开头的地方把其中的call指令改成call 00FD7AB4
                       直接到达了游戏成功应该在的位置
    eax=0046F5D8, (ASCII "zsctf{T9is_tOpic_1s_v5ry_int7resting_b6t_others_are_n0t}")

    终于啊!!!
     
    它的内存的各种mov操作把字符一个接一个压到栈中,后来又一波操作整个打印出来
    F4的作用是,一下循环一次

知识点:
    

  • 1 按计数寄存器 ((E)CX) 中指定的次数重复执行字符串指令,直到寄存器 (E)CX 中的计数递减到 0,或是重复到 ZF 标志不再满足指定的条件。REP(重复)、REPE(相等时重复)、REPNE(不相等时重复)、REPZ(为零时重复)及 REPNZ(不为零时重复)助记符都是可以添加到一些字符串指令中的前缀。REP 前缀可以添加到 INS、OUTS、MOVS、LODS 及 STOS 指令,REPE、REPNE、REPZ 及 REPNZ 前缀可以添加到 CMPS 与 SCAS 指令。(REPZ 与 REPNZ 前缀分别是 REPE 与 REPNE 前缀的同义形式)。同非字符串指令一起使用时,REP 前缀的行为未定义。
  •     REP 前缀一次只能应用于一条字符串指令

     

  •     2stos 包括 stosb   stosw   stosd, 涉及的寄存器是eax, edi, 功能如下:
         stosb    将al中的值复制到 byte ptr es:[edi] 中, 同时edi++
         stosw    将ax中的值复制到 word ptr es:[edi] 中, 同时edi++
         stosd    将eax中的值复制到 dword ptr es:[edi] 中, 同时edi++ 
         int b[0x33];
         __asm            //下面这三句汇编语句用来初始化数组b, 简单高效
         {
           XOR EAX, EAX                 lea edi, b
           mov ecx, 0x33
           rep stosd
         }
        指令,       终止条件1,终止条件2
        REP,        ECX=0,     无            
        kREPE/REPZ, ECX=0,     ZF=0
        REPNE/REPNZ,ECX=0,     ZF=1 
        
        mov     eax,0CCCCCCCCh             //int3中断,0CCCCCCCCh相当于0xCCCCCCCC,这段代码是初始化堆栈和分配局部 变量用的,往分配好的局部变量空间放入int3中断的原因是:防止该空间里的东东被意外执行。 
        rep stos dword ptr es:[edi]      //重复stos指令ecx中值的次数

 

  •     3
    %p是专门打印地址的, %x是以十六进制形式打印数据    
         打印size_t 类型的值时要小心。这是无符号值,如果选错格式说明符,可能会得到不可靠的结果。推荐的格式说明符是%zu
         size_t 用做sizeof 操作符的返回值类型,同时也是很多函数的参数类型,包括malloc 和strlen。它是无符号整数

     

  •     4 本题的贪心算法
    我们只需要考虑是否按下第一个灯。因为如果第一个灯的状态被确定了,那么是否按下第二个灯也就决定了(如果第一个灯与期望不同,则按下,如果期望相同,则不按下)同理,第三个灯是否按下也唯一确定。所以,本题只要分两种情况:灯1被按下和没有被按下之后使用for循环判断别的灯是否需要按下即可当循环结束,若现在的灯况与答案相同,则输出两种方案中按键次数最少的,若不同,则impossible!
        ACM特殊密码锁:我们这个题不适用,因为我们的第一个就算是确定还有最后一个可以影响它
    #include
    #include
    #include
    using namespace std;
    string lockin,lockout;
    int L1[35],L2[35],L3[35];
    int main(){
    
        int num1=0,num2=0;
        cin>>lockin>>lockout;
        int len=lockin.length();
        for(int i=0;i

     

  •    5
    INT3断点是断点的一种,在诸如Ollydbg中的快捷键是F2,是一种很常用的断点类型。INT3指令的机器码为CC,所以通常也称之为CC指令。用INT3断点的好处是可以设置无数个断点,缺点是改变了原程序指令,容易被软件检测到。例如为了防范API被下断,一些软件会检测API的首地址是否为CCh,以此来判断是否被下了断点

 

 

你可能感兴趣的:(逆向工程)