ida动调

hello,大家好,今天给大家讲解一下0xgame一个入门逆向的两种做法

首先,我们下载下来之后用ida打开

之后我们需要找到输入点,以及password

shift+F12打开字符串 搜索password

点击x交叉引用,F5反编译,可以看到输入的逻辑

N重命名一下为了好看一点

之后我们x再引用一下,我们发现上面一层是主函数

我们在这里F2打上断点,然后看一下输入点是不是和我们想的一样

F9启动调试,选中这个

之后一直F8,看看哪里卡住,这里F8是单步,并不会进入函数里面

这里我们就看到运行到我们之前定义的那个函数就停住了,所以说那个是输入点

具体的话就是这一行

  if ( !fgets(Buffer, 64, Stream_2) )
    return 1;

我们再输入行之后再打上断点,避免运行之后直接结束

可以看到,这里走入我们的断点的位置了

之后我们根据大体的功能命名一下

这里我们看到加密的区域块,在命名第二个函数的时候

我们在deal1和deal2这里分别打上断点,看看这个密码输入后的这两个函数在实现什么功能

我们点击F9直接进入到我们的断点的位置,之后点击F7进入函数内部

中间的话需要F5和Tab来回切换层级看,这里的话就不展开了,有点多

之后我们这里进入上述的那一串的字符的区域,这里发现ida是给我们识别出来了

我们在识别出来的基础点击P即可

假如说自己主动还原的话,先点击U,然后点击C,最后点击P即可

这里我们就可以看到deal2的具体逻辑了

__int64 __fastcall deal2(__int64 a1)
{
  deal1(
    lpAddress_,
    (char *)sub_7FF719AA25F4 - (char *)lpAddress_,
    (__int64)&unk_7FF719AA50E0,
    (__int64)&unk_7FF719AA5130);
  return ((__int64 (__fastcall *)(__int64))lpAddress_[0])(a1);
}

这里下面这一串同样是一个区域加密

我们仍旧是F2打断点到函数的上面,然后F9过去,之后再F7进入

这里可以看到ida帮助我们还原了

这里我们再点击P即可

这里我们就能成功的看到程序的核心校验逻辑了

之后两种做法从这里分开讲

做法一:patch

之后我们一直F8走,看看正确和错误的分支

这里可以看到错误是走的这个分支,正确的那个仍旧走的是内存解密

这里内存解密应该是输出的flag逻辑我们猜测

这里选中rip的寄存器的,之后点击E,写上我们跳转的地址点击确定

之后这里看到成功的输出了我们的flag

做法二:加密

这里的话就是一个算法,这里的话是大端序的转化

后面的那一行加密算法,就是一个异或,循环移位,加减

转化一下顺序就可以了

target = 0x6E4EA9AABAEB2EB4
#   __ROL8__(src ^ 0x819173B095485D69, 21) - 0x1E277ACA3E3B2E23) ^ 0xF216C53D78B72357 = target
#  target = (ROL64(src ^ A, 21) - D) ^ B;
#  src = ROR64(((target ^ B) + D) , 21) ^ A;
def ROR64(x, n):
    return (x >> n) | (x << (64 - n)) & 0xFFFFFFFFFFFFFFFF
src = ROR64(((target ^ 0xF216C53D78B72357)+ 0x1E277ACA3E3B2E23),21) ^ 0x819173B095485D69
print(src.to_bytes(8, byteorder="big").decode("ascii"))

附录

这个题目的出题的话,主要是依据的这个函数VirtualProtect,这个和解锁编辑权限之后crypto修改,后面再利用VirtualProtect这个函数回复权限

BOOL __fastcall deal1(void *lpAddress_1, SIZE_T dwSize_1, __int64 a3, __int64 a4)
{
  HANDLE hProcess; // rax
  DWORD flOldProtect; // [rsp+2Ch] [rbp-94h] BYREF
  __int64 v7[18]; // [rsp+30h] [rbp-90h] BYREF

  VirtualProtect(lpAddress_1, dwSize_1, 0x40u, &flOldProtect);
  crypto1((__int64)v7, a3, a4, 0);
  crypto2((__int64)v7, (__int64)lpAddress_1, (__int64)lpAddress_1, dwSize_1);
  VirtualProtect(lpAddress_1, dwSize_1, flOldProtect, &flOldProtect);
  hProcess = GetCurrentProcess();
  return FlushInstructionCache(hProcess, lpAddress_1, dwSize_1);
}

好了,实现的原理主要是如下啦,感谢大家观看