20211028gfsj_re_easyhook

运行一下熟悉流程,拿去查壳发现无壳,C++编译32位

拿去IDA看一下伪代码

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  HANDLE v4; // eax
  DWORD NumberOfBytesWritten; // [esp+4h] [ebp-24h]
  char Buffer; // [esp+8h] [ebp-20h]

  sub_401370(aPleaseInputFla);
  scanf(a31s, &Buffer);
  if ( strlen(&Buffer) == 19 )//输入长度19
  {
    sub_401220();
    v4 = CreateFileA(FileName, 0x40000000u, 0, 0, 2u, 0x80u, 0);
    WriteFile(v4, &Buffer, 0x13u, &NumberOfBytesWritten, 0);
    sub_401240(&Buffer, &NumberOfBytesWritten);//flag与NumberOfBytesWritten有关?
    if ( NumberOfBytesWritten == 1 )
      sub_401370(aRightFlagIsYou);
    else
      sub_401370(aWrong);
    system(aPause);
    result = 0;
  }
  else
  {
    sub_401370(aWrong);
    system(aPause);
    result = 0;
  }
  return result;
}

signed int __cdecl sub_401240(const char *a1, _DWORD *a2)
{//a1=Buffer,a2=NumberOfBytesWritten
  signed int result; // eax
  unsigned int v3; // kr04_4
  char v4[24]; // [esp+Ch] [ebp-18h]

  result = 0;
  strcpy(v4, "This_is_not_the_flag");//strlen(v4)=20
  v3 = strlen(a1) + 1;
  if ( (signed int)(v3 - 1) > 0 )
  {
    while ( v4[a1 - v4 + result] == v4[result] )
    {//a1=v4
      if ( ++result >= (signed int)(v3 - 1) )
      {
        if ( result == 21 )
        {
          result = (signed int)a2;
          *a2 = 1;//NumberOfBytesWritten=1
        }
        return result;
      }
    }
  }
  return result;
}

发现sub_401240()只是类似于strcmp函数,不是加密所在,这已经是加密后用来对比了,往前看看上面三条语句。后面两个为API函数。API函数可以不管,因为它只是进行了打开文件和写入数据操作。重点看sub_401220。

HANDLE CreateFileA(
  LPCSTR                lpFileName,				//要创建或打开的文件或设备的名称
  DWORD                 dwDesiredAccess,		//所请求的对文件或设备的访问,可以分为读、写或者合在一起,0x40000000表示写
  DWORD                 dwShareMode,			//请求共享模式。对其属性或扩展属性的访问请求进行约束,0表示阻止其他进程在请求删除,读取或写入访问时打开文件或设备。
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,	//习惯为NULL
  DWORD                 dwCreationDisposition,	//对存在或不存在的文件或设备执行的操作。2表示总是创建
  DWORD                 dwFlagsAndAttributes,	//文件或设备属性和标志
  HANDLE                hTemplateFile			//具有GENERIC_READ访问权限的模板文件的有效句柄。
);
BOOL WriteFile(
HANDLE  hFile,//文件句柄,需要写入数据的文件指针
LPCVOID lpBuffer,//数据缓存区指针
DWORD   nNumberOfBytesToWrite,//要写入的字节数,0x13=19
LPDWORD lpNumberOfBytesWritten,//用于保存实际写入字节数的存储区域的指针
LPOVERLAPPED lpOverlapped//OVERLAPPED结构体指针
);
int sub_401220()
{
  HMODULE v0; // eax
  DWORD v2; // eax

  v2 = GetCurrentProcessId();//获取当前进程一个唯一的标识符
  hProcess = OpenProcess(0x1F0FFFu, 0, v2);//打开一个已存在的进程对象,并返回进程的句柄
  v0 = LoadLibraryA(LibFileName);//将指定的lib加载到调用进程的地址空间中
  dword_40C9C4 = (int)GetProcAddress(v0, ProcName);//检索指定的动态链接库(DLL)中的输出库函数地址,ProcName=WriteFile,也就是调用库中的WriteFile函数
  //返回值:如果函数调用成功,返回值是DLL中的输出函数地址。如果函数调用失败,返回值是NULL。
  lpAddress = (LPVOID)dword_40C9C4;//WriteFile函数地址
  if ( !dword_40C9C4 )
    return sub_401370((int)aApi);
  unk_40C9B4 = *(_DWORD *)lpAddress;//将WriteFile函数地址存到内存中
  *((_BYTE *)&unk_40C9B4 + 4) = *((_BYTE *)lpAddress + 4);
  byte_40C9BC = -23;//-23=0xE9	//jmp的机器码是0xE9,后面紧跟4个字节是偏移地址
  dword_40C9BD = (char *)sub_401080 - (char *)lpAddress - 5;
    //偏移地址 = 目标地址 - 当前地址 - 5
  return sub_4010D0();
}

依次进入各个函数

int __stdcall sub_401080(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)//sub_401080相当于也是个WriteFile函数
//接受哪里的参数?我们输入之后,就再也没有对输入的字符串做任何操作,所以参数应该是我们输入的字符串与字符串长度
{
  signed int v5; // ebx

  v5 = sub_401000((int)lpBuffer, nNumberOfBytesToWrite);
  sub_401140();
  WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
  if ( v5 )
    *lpNumberOfBytesWritten = 1;//最终打印出“correct”是因为这个,而不是因为sub_401240()
  return 0;
}
signed int __cdecl sub_401000(int a1, signed int a2)
{//a1=输入的字符串,a2=字符串长度
  char v2; // al
  char v3; // bl
  char v4; // cl
  int v5; // eax

  v2 = 0;
  if ( a2 > 0 )
  {
    do
    {
      if ( v2 == 18 )
      {
        *(_BYTE *)(a1 + 18) ^= 0x13u;//a1[18]=a1[18]^0x13
      }
      else
      {
        if ( v2 % 2 )
        //下标奇数执行if,下标偶数执行else
          v3 = *(_BYTE *)(v2 + a1) - v2;//v3=a1[i]-i
        else
          v3 = *(_BYTE *)(v2 + a1 + 2);//v3=a1[i+2]
        
        *(_BYTE *)(v2 + a1) = v2 ^ v3;//a1[i]=i^v3
      }
      ++v2;
    }
    while ( v2 < a2 );
  }
  v4 = 0;
  if ( a2 <= 0 )
    return 1;
  v5 = 0;
  while ( byte_40A030[v5] == *(_BYTE *)(v5 + a1) )
  {//a1[i]=byte_40A030[i]
    v5 = ++v4;
    if ( v4 >= a2 )
      return 1;
  }
  return 0;
}
.data:0040A030 ; char byte_40A030[20]
.data:0040A030 byte_40A030     db 61h                  ; DATA XREF: sub_401000:loc_401051↑r
.data:0040A031                 db  6Ah ; j
.data:0040A032                 db  79h ; y
.data:0040A033                 db  67h ; g
.data:0040A034                 db  6Bh ; k
.data:0040A035                 db  46h ; F
.data:0040A036                 db  6Dh ; m
.data:0040A037                 db  2Eh ; .
.data:0040A038                 db  7Fh ; 
.data:0040A039                 db  5Fh ; _
.data:0040A03A                 db  7Eh ; ~
.data:0040A03B                 db  2Dh ; -
.data:0040A03C                 db  53h ; S
.data:0040A03D                 db  56h ; V
.data:0040A03E                 db  7Bh ; {
.data:0040A03F                 db  38h ; 8
.data:0040A040                 db  6Dh ; m
.data:0040A041                 db  4Ch ; L
.data:0040A042                 db  6Eh ; n
.data:0040A043                 db    0

exp

    int byte_40A030[20] = { 0x61, 0x6a, 0x79, 0x67, 0x6b, 0x46, 0x6d, 0x2e, 0x7f, 0x5f, 0x7e, 0x2d, 0x53, 0x56, 0x7b, 0x38, 0x6d, 0x4c, 0x6e, 0 };
    int flag[20] = { 0 };
    int v3[20];
    int i;
    flag[18] = byte_40A030[18] ^ 0x13;
    for (i = 0; i < 20; i++)
    {
        v3[i] = i ^ byte_40A030[i];
    }
    for (i = 0; i < 19; i++)
    {
        if (i % 2)
            flag[i] = v3[i] + i;
        else
        {
            if (i != 18)
                flag[i + 2] = v3[i];
        }
        printf("%c", (char)flag[i]);
    }
//lag{Ho0k_w1th_Fun}

那个“f”应该是推不出来?还是我太菜了,反正最终flag

flag{Ho0k_w1th_Fun}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值