CTF中的时间验证 及 ctypes

参考:
https://www.52pojie.cn/thread-742361-1-1.html

flag only appears at a specific time, range [2018-05-19 09:00, 2018-05-21 09:00)
Better luck next time :)

使用IDA分析该二进制文件,在函数表中可以找到main函数,在main函数的头部打下断点并调试运行,这时能够发现在该断点命中的时候屏幕上已经有信息输出,说明在main函数之前还执行了大量的代码(MFC和win的onInitDialog之类)。如何寻找真正的入口函数呢?方法有如下:main函数栈回溯、puts栈回溯

imports里有time64
在这里插入图片描述

__int64 __fastcall sub_402268(__time64_t *a1, __int64 a2)
{
  __int64 result; // rax
  unsigned int v3; // [rsp+20h] [rbp-10h]
  int v4; // [rsp+24h] [rbp-Ch]
  unsigned int v5; // [rsp+28h] [rbp-8h]
  int i; // [rsp+2Ch] [rbp-4h]

  v5 = time64(a1);
  if ( v5 <= 0x5AFFE78F || v5 > 0x5B028A8F )
    return 0LL;
  srand((unsigned int)a1);
  for ( i = 0; i <= 255; ++i )
    byte_405020[i] ^= rand();
  v4 = 0;
  v3 = 0;
  sub_4027ED((__int64)a1, a2, &v4, (__int64)byte_405020, &v3);
  if ( v4 == 0x700 )
  {
    unk_4099D0 = v3;
    result = v3;
  }
  else
  {
    unk_4099D0 = 0;
    result = 0LL;
  }
  return result;
}

time64函数返回当前时间戳,根据这段代码,返回的时间戳应该在(0x5AFFE78F,0x5B028A8F]这个范围内程序才会继续执行。
其后以时间戳做为随机数种子,取随机数对E1表异或运算,再通过4027ED这个函数对byte_405020表进行一些变换,最终得到v4的值,并判断v4的值是否等于0x700.
在后面的代码中可知,如果unk_4099D0等于0,那么程序将直接退出。因此,必须要寻找一个值使得v4满足v4==0x700。
我们观察满足题意的time返回值,0x5B028A8F - 0x5AFFE78F = 0x2A300,可以说是非常小的数字了,只需要遍历测试(0x5AFFE78F,0x5B028A8F]区间的所有值即可寻找到正确的time值。

c语言解题脚本

添加对应函数头文件,照百度解决memcpy的aceess violation问题
改了工程设置里的,链接器,高级,数据执行保护为“否”

#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned int(*test)();
static UINT time = 0x5AFFE78F + 1; //起点
UINT myfun(int) { //通过这种形式遍历每一个time
        return time++;
}
char e1_copy[256] = {0};
int main()
{
        UINT64 * ptr1 = (UINT64 *)0x40A38C;//time64
        UINT64 * ptr2 = (UINT64 *)0x40A414; //srand
        UINT64 * ptr3 = (UINT64 *)0x40A3FC;//rand
        UINT64 * ptr4 = (UINT64 *)0x40A3DC;//memset
        HMODULE h = LoadLibraryA("C:\\Users\\lenovo\\Desktop\\fuxian\\magic\\magic.exe");
        memcpy(e1_copy, (void *)0x405020, 256); //备份E1表,重新运算的时候需要还原E1表
        test test1 = (test)0x402268;
        *ptr1 = (UINT64)myfun;
        *ptr2 = (UINT64)srand;
        *ptr3 = (UINT64)rand;
        *ptr4 = (UINT64)memset;
        UINT val;
        while (true)
        {
                memcpy((void *)0x405020, e1_copy, 256); // 重置E1表
                val =  test1();
                if (val != 0)
                {
                        printf("time:%x\nkey:%x", time -1 , val); //0x322ce7a4
                        //time:5b00e398
                        //key: 322ce7a4
                        break;
                }
        }
    return 0;
}

在这里插入图片描述

Bypass ctypes

import ctypes
def h2f(s):
    cp = ctypes.pointer(ctypes.c_int(s))
    fp = ctypes.cast(cp, ctypes.POINTER(ctypes.c_float))
    return fp.contents.value
def f2h(s):
    fp = ctypes.pointer(ctypes.c_float(s))
    cp = ctypes.cast(fp, ctypes.POINTER(ctypes.c_int))
    return cp.contents.value
if __name__=='__main__':
    X=0
    score=0
    while(int(((1.5-h2f(X)*h2f(X)*(score/2))*h2f(X)*100000000*10+5)/10)!=0x436AE):
        score+=1
        X=0x5F3759D8 - (f2h(score)>>1)
        if X!=0:
            X+=7
    print score
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

q1uTruth

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值