逆向入门学习-【Base64 编码逆向 Base64 变表逆向 IDA 动态调试 IDA 8.3 IDA 动态调试解RC4 绕过反调试 IDA 代码修复 & 数组识别 】

异或

在这里插入图片描述

Base64 编码逆向

在这里插入图片描述
Base64 编码是一种用于将二进制数据转换为文本字符串的编码方式。它常用于在文本协议中传输二进制数据,或者用于存储二进制数据在文本文件中。

当遇到某些很复杂的函数时,可以寻找函数中使用到的常量,然后去搜索引擎上搜索,有可能能够找到相关源码,然后进行比对

/*base64.c*/  
#include "base64.h"  
  
unsigned char *base64_encode(unsigned char *str)  
{  
    long len;  
    long str_len;  
    unsigned char *res;  
    int i,j;  
//定义base64编码表  
    unsigned char *base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";  
  
//计算经过base64编码后的字符串长度  
    str_len=strlen(str);  
    if(str_len % 3 == 0)  
        len=str_len/3*4;  
    else  
        len=(str_len/3+1)*4;  
  
    res=malloc(sizeof(unsigned char)*len+1);  
    res[len]='\0';  
  
//以3个8位字符为一组进行编码  
    for(i=0,j=0;i<len-2;j+=3,i+=4)  
    {  
        res[i]=base64_table[str[j]>>2]; //取出第一个字符的前6位并找出对应的结果字符  
        res[i+1]=base64_table[(str[j]&0x3)<<4 | (str[j+1]>>4)]; //将第一个字符的后位与第二个字符的前4位进行组合并找到对应的结果字符  
        res[i+2]=base64_table[(str[j+1]&0xf)<<2 | (str[j+2]>>6)]; //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符  
        res[i+3]=base64_table[str[j+2]&0x3f]; //取出第三个字符的后6位并找出结果字符  
    }  
  
    switch(str_len % 3)  
    {  
        case 1:  
            res[i-2]='=';  
            res[i-1]='=';  
            break;  
        case 2:  
            res[i-1]='=';  
            break;  
    }  
  
    return res;  
}  
  
unsigned char *base64_decode(unsigned char *code)  
{  
//根据base64表,以字符找到对应的十进制数据  
    int table[]={0,0,0,0,0,0,0,0,0,0,0,0,
    		 0,0,0,0,0,0,0,0,0,0,0,0,
    		 0,0,0,0,0,0,0,0,0,0,0,0,
    		 0,0,0,0,0,0,0,62,0,0,0,
    		 63,52,53,54,55,56,57,58,
    		 59,60,61,0,0,0,0,0,0,0,0,
    		 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,0,0,0,0,0,0,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
    	       };  
    long len;  
    long str_len;  
    unsigned char *res;  
    int i,j;  
  
//计算解码后的字符串长度  
    len=strlen(code);  
//判断编码后的字符串后是否有=  
    if(strstr(code,"=="))  
        str_len=len/4*3-2;  
    else if(strstr(code,"="))  
        str_len=len/4*3-1;  
    else  
        str_len=len/4*3;  
  
    res=malloc(sizeof(unsigned char)*str_len+1);  
    res[str_len]='\0';  
  
//以4个字符为一位进行解码  
    for(i=0,j=0;i < len-2;j+=3,i+=4)  
    {  
        res[j]=((unsigned char)table[code[i]])<<2 | (((unsigned char)table[code[i+1]])>>4); //取出第一个字符对应base64表的十进制数的前6位与第二个字符对应base64表的十进制数的后2位进行组合  
        res[j+1]=(((unsigned char)table[code[i+1]])<<4) | (((unsigned char)table[code[i+2]])>>2); //取出第二个字符对应base64表的十进制数的后4位与第三个字符对应bas464表的十进制数的后4位进行组合  
        res[j+2]=(((unsigned char)table[code[i+2]])<<6) | ((unsigned char)table[code[i+3]]); //取出第三个字符对应base64表的十进制数的后2位与第4个字符进行组合  
    }  
  
    return res;  
  
}  

Base64 变表逆向

在这里插入图片描述

IDA 动态调试 IDA 8.3

我们可以通过动态调试知道某些值或者其变化,也可以通过观察函数前后相关值的变化进而猜测其功能

在Windows机器上运行IDA可以直接动态调试exe文件,但不可以调试elf文件。
如果需要调试elf文件需要选择远程调试

远程调试参考链接

将Windows上的IDA的服务器组件移动到Ubuntu上去

在这里插入图片描述
linux_server:在Linux计算机上执行的、用于调试32位Linux应用程序的服务器组件。
linux_server64:在64位Linux计算机上执行的、用于调试64位Linux应用程序的服务器组件。

运行组件

根据要调试的elf文件类型运行不同组件
在这里插入图片描述

IDA选择调试器

在这里插入图片描述

选择设置

在这里插入图片描述
OK后
在这里插入图片描述

相关动态调试功能

在这里插入图片描述
run to cursor:运行到光标

快捷键A:尝试将一段数据制定为字符串字面量(String Literal)

IDA 动态调试解RC4

在这里插入图片描述
也是根据输入输出来猜测

绕过反调试

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  int j; // [esp+31Ch] [ebp-69Ch]
  int i; // [esp+328h] [ebp-690h]
  size_t v6; // [esp+334h] [ebp-684h]
  char v7[55]; // [esp+340h] [ebp-678h]
  char v8; // [esp+377h] [ebp-641h]
  unsigned int v9; // [esp+380h] [ebp-638h]
  int v10; // [esp+38Ch] [ebp-62Ch]
  char Str[520]; // [esp+398h] [ebp-620h] BYREF
  char v12[264]; // [esp+5A0h] [ebp-418h] BYREF
  char v13[264]; // [esp+6A8h] [ebp-310h] BYREF
  char v14[516]; // [esp+7B0h] [ebp-208h] BYREF

  __CheckForDebuggerJustMyCode(&unk_49C00F);
  j__memset(v14, 0, 0x200u);
  j__memset(v13, 0, 0x100u);
  j__memset(v12, 0, 0x100u);
  j__memset(Str, 0, 0x200u);
  v10 = 0;
  v9 = 0;
  v7[0] = -28;
  v7[1] = 21;
  v7[2] = -60;
  v7[3] = -19;
  v7[4] = -90;
  v7[5] = 47;
  v7[6] = 86;
  v7[7] = 16;
  v7[8] = -69;
  v7[9] = 19;
  v7[10] = -21;
  v7[11] = -83;
  v7[12] = 117;
  v7[13] = 86;
  v7[14] = -57;
  v7[15] = -69;
  v7[16] = -69;
  v7[17] = -23;
  v7[18] = -71;
  v7[19] = -52;
  v7[20] = 2;
  v7[21] = 58;
  v7[22] = 80;
  v7[23] = -97;
  v7[24] = 54;
  v7[25] = -112;
  v7[26] = 105;
  v7[27] = -66;
  v7[28] = 124;
  v7[29] = 66;
  v7[30] = 68;
  v7[31] = -54;
  v7[32] = -58;
  v7[33] = -44;
  v7[34] = 36;
  v7[35] = 92;
  v7[36] = -46;
  v7[37] = -71;
  v7[38] = 36;
  v7[39] = -63;
  v7[40] = 24;
  v7[41] = -109;
  v7[42] = -77;
  v7[43] = -22;
  sub_42F057(v14);
  sub_42C40B("Welcome!! give me your flag:\n");
  do
  {
    v8 = j_j_j___fgetchar();
    if ( v8 == 10 )
      break;
    Str[v9++] = v8;
  }
  while ( (int)v9 < 44 );
  if ( v9 >= 0x200 )
    j____report_rangecheckfailure();
  Str[v9] = 0;
  v6 = j__strlen(Str);
  sub_42CEFB(v13, v14, v6);
  for ( i = 0; i < 256; ++i )
    v12[i] = v13[i];
  sub_42D5B8(v13, Str, v6);
  for ( j = 0; j < 44; ++j )
  {
    if ( v7[j] == Str[j] )
      ++v10;
  }
  if ( v10 == 44 )
    sub_42C40B("Yes, u right!\n");
  else
    sub_42C40B("no no no\n");
  sub_42D0CC("pause");
  return 0;
}

反调试函数

  __CheckForDebuggerJustMyCode(&unk_49C00F);
………
………
  sub_42F057(v14);

sub_42f057()

_BYTE *__cdecl sub_4325D0(_BYTE *a1)
{
  HWND ForegroundWindow; // eax
  unsigned __int64 v2; // rax
  unsigned __int64 v3; // rax
  int v5; // [esp+25Ch] [ebp-438h]
  CHAR String[1028]; // [esp+28Ch] [ebp-408h] BYREF

  if ( IsDebuggerPresent() )
    *a1 = 89;
  else
    *a1 = 88;
  ForegroundWindow = GetForegroundWindow();
  GetWindowTextA(ForegroundWindow, String, 1023);
  if ( j__strstr(String, "WinDbg")
    || j__strstr(String, "x64dbg")
    || j__strstr(String, "x32dbg")
    || j__strstr(String, "OllyICE")
    || j__strstr(String, "OllyDBG")
    || j__strstr(String, "Immunity") )
  {
    a1[1] = 111;
  }
  else
  {
    a1[1] = 48;
  }
  SetLastError((DWORD)"12345");
  OutputDebugStringW("Test for debugger!");
  if ( (char *)GetLastError() == "12345" )
    a1[2] = 110;
  else
    a1[2] = 117;
  if ( !CloseHandle((HANDLE)0x1234) && GetLastError() == 6 )
    a1[3] = 66;
  else
    a1[3] = 65;
  if ( NtCurrentPeb()->BeingDebugged )
    a1[4] = 97;
  else
    a1[4] = 64;
  v2 = __rdtsc();
  v5 = v2;
  v3 = __rdtsc();
  if ( (unsigned int)(v3 - v5) >= 0xFF )
    a1[5] = 100;
  else
    a1[5] = 68;
  a1[6] = 0;
  return a1;
}

此时需要使用atttach调试来绕过反调试
核心就是使得程序在非调试条件下正常运行过调试函数后再介入调试
先用IDA打开对应文件,在反调试函数后同时是exe此时还没运行的地方下断点
在这里插入图片描述

选择调试器
在这里插入图片描述
直接运行exe文件
在这里插入图片描述
在这里插入图片描述
选择对应运行的exe文件
在这里插入图片描述
此时程序会固定停在此处
在这里插入图片描述
然后continue
在这里插入图片描述
然后输入
在这里插入图片描述
停在之前所设断点处
在这里插入图片描述
此时即可调试了

IDA 代码修复 & 数组识别

根据某些暗示将数组合并为一个大数组

可以先根据熟悉函数判断相关变量类型进而确定某些函数的参数类型
根据陌生函数实际用处和定义来修改参数类型和返回值类型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

看星猩的柴狗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值