跳转至

简单逆向练习

passkey

C
#include <stdio.h>
#include <string.h>

int checkpass(const char* passkey);

int main() {
    // user input for password
    char passkey[100];
    printf("Enter your password: ");
    scanf("%99s", passkey);
    checkpass(passkey);

    return 0;
}

int checkpass(const char* passkey) {
    int minLength = 6;
    int maxLength = 20;
    if (strlen(passkey) < minLength || strlen(passkey) > maxLength) {
        printf("Password length must be between %d and %d characters.\n", minLength, maxLength);
        return 0;
    }
    // define xor key
    const char* xorKey = "mysecretkey";
    // define correct password
    const char* correctPassword = "securepassword";
    // xor ecrypt the input password and compare with correct password
    for (int i = 0; i < strlen(correctPassword); i++) {
        if ((passkey[i] ^ xorKey[i % strlen(xorKey)]) != correctPassword[i]) {
            printf("Incorrect password.\n");
            return 0;
        }
    }
    return 1;
}

编译

Text Only
gcc -m32 test.c -o passkey.exe

image-20260106215816494

首先找到主函数,现在我们想要破解该程序,有两种思路,第一种是找到正确的key,第二种是修改程序的判断逻辑,现在将分别基于这两种方法进行操作


方法一(基于伪C代码)

首先将反汇编转换为伪C代码

C
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char Str[100]; // [esp+1Ch] [ebp-64h] BYREF

  __main();
  printf("Enter your password: ");
  scanf("%99s", Str);
  checkpass(Str);
  return 0;
}

显然核心逻辑在于checkpass函数,我们查看checkpass函数的伪C代码

C
int __cdecl checkpass(char *Str)
{
  size_t i; // eax
  size_t v3; // [esp+3Ch] [ebp-Ch]

  if ( strlen(Str) >= 6 && strlen(Str) <= 0x14 )
  {
    v3 = 0;
    for ( i = strlen("securepassword"); v3 < i; i = strlen("securepassword") )
    {
      if ( ((unsigned __int8)aMysecretkey[v3 % strlen("mysecretkey")] ^ (unsigned __int8)Str[v3]) != aSecurepassword[v3] )
      {
        puts("Incorrect password.");
        return 0;
      }
      ++v3;
    }
    return 1;
  }
  else
  {
    printf("Password length must be between %d and %d characters.\n", 6, 20);
    return 0;
  }
}

我们将这两段代码结合一下,放在代码编辑器中查看

image-20260106220637943

显然存在很多报错,我们一步步尝试一步步还原代码:

  1. 首先补全头文件

可以看到使用了printf和strlen函数,那么需要补充如下头文件

Text Only
#include <stdio.h>
#include <string.h>
  1. 补全缺失的变量(aSecurepassword, aMysecretkey)

根据代码,这两个变量就是字符串securepassword和mysecretkey

  1. 删除不必要的__main函数

还原后结果:

C
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

int checkpass(char* Str)
{
    size_t length; // eax
    size_t v3; // [esp+3Ch] [ebp-Ch]

    // 补全缺失的变量(aSecurepassword, aMysecretkey)
    const char* aMysecretkey = "mysecretkey";
    const char* aSecurepassword = "securepassword";

    if (strlen(Str) >= 6 && strlen(Str) <= 20)  // 0x14 = 20
    {
        v3 = 0;
        for (length = strlen("securepassword"); v3 < length; ++v3 )  // 显然i为length, 并将++v3上移
        {
            if (((unsigned __int8)aMysecretkey[v3 % strlen("mysecretkey")] ^ (unsigned __int8)Str[v3]) != aSecurepassword[v3])
            {
                puts("Incorrect password.");
                return 0;
            }

        }
        return 1;
    }
    else
    {
        printf("Password length must be between %d and %d characters.\n", 6, 20);
        return 0;
    }
}

int __cdecl main(int argc, const char** argv, const char** envp)
{
    char Str[100]; // [esp+1Ch] [ebp-64h] BYREF

    // 删除不必要的__main函数
    printf("Enter your password: ");
    scanf("%99s", Str);
    checkpass(Str);
    return 0;
}

那么显然该程序首先判断输入的passkey是否在6和20之间,随后逐字节将输入的passkey与aMysecretkey变量异或,并判断是否与aSecurepassword变量相等,由于异或的特性,存在a^b^b = a,假设a^b = c,那么如果我们已知b和c,想要得到a,只需要计算b^c即可,带入代码可得:

Text Only
由于passkey ^ aMysecretkey ^ aMysecretkey = passkey
且passkey ^ aMysecretkey = aSecurepassword
所以aSecurepassword ^ aMysecretkey = passkey

解密代码如下:

Python
def main():
    aSecurepassword = "securepassword"
    aMysecretkey = "mysecretkey"
    # calculate xor of two strings
    passkey = ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(aSecurepassword,
                                                           aMysecretkey))
    print("XOR Result:", passkey)


if __name__ == "__main__":
    main()

image-20260106223536173


方法二(修改程序判断逻辑)

AES版本

上文我们练习了异或算法,这次我们练习更常见的AES算法