逆向工程

腾讯面试Crackme逆向分分析

2018-04-03  本文已影响96人  Killshadow

CrackMe2逆向分析

系统:Windows10 企业版 1709(部分测试在Win7虚拟机)

OD版本:吾爱专版(包含:API断点设置插件)

IDA版本:7.0

截图工具:Snipaste

文本编辑器:Typora

题目下载:链接:https://pan.baidu.com/s/15tqCH-Uj8YScej-whvv9Fg 密码:api7

一、脱壳

  1. 查壳

    image.png

    看到yoda的,大部分都是PEiD误报,又用Exeinfo PE查了一下,也没有找到特征壳,看来不是市场上常见壳。

    image.png
  2. 尝试脱壳

    00401830 > $- E9 B71D0100      jmp crackme2.004135EC
    00401835   .  9C               pushfd
    00401836   .  873424           xchg dword ptr ss:[esp],esi              ;  crackme2.<ModuleEntryPoint>
    00401839   .  8B3424           mov esi,dword ptr ss:[esp]               ;  kernel32.749E8654
    0040183C   .  8B3424           mov esi,dword ptr ss:[esp]               ;  kernel32.749E8654
    

    第一行程序入口便是一个jmp大跳,尝试直接F4在00401835下断,程序直接执行了,无法调试。用单步法往下执行,没用(没有往上jump)。ESP大法下硬断,直接跳到程序逻辑了。那就先不脱壳吧,先看看程序验证算法。

二、程序算法分析

  1. 根据程序运行逻辑下API断

    看到有用户名、密码输入框,这两个字符串都要拷贝到一个缓存区内,猜测用了GetWindowTextGetDlgItemTextA,于是下了下面四个断:

    下API断点.png
    然后F9,随便输入用户名密码:
    尝试输入密码.png
    再F9之后,四个断都用上了,然后Ctrl+F9跳到retn,回到程序领空之后一直单步看逻辑。
  2. 获取用户名长度

    004165E1    F2:AE       repne scas byte ptr es:[edi]
    

    执行到这一步的时候,看到repne scas可知在获取用户名字串长度,猜测应该是后面对用户名操作,需要根据用户名长度加循环。

    获取用户名长度.png
    ecx从FFFFFFFF开始,每循环一次ecx-1,edi左移以删除第一个字符,最终edi的值为00停止循环,图中通过ecx的值可以看出字符串长度为7。
  3. 分析循环过程

    调了半天,最后定位密码生成算法在004064B3——004074F5内存空间里,主要步骤:

    • 操作1: 操作1.png
    • 操作2: 操作2.png
    • 操作3: 操作3-5.png
  4. 密码验证分析

    • 循环过后,跳出密码生成循环,能看到密码,很惊讶密码没有加密: 5密码.png
    • 经过几个大跳之后,找到关键比较: 7关键比较.png
    • 比较完密码第一个字符串是错误之后,就到了关键跳: 6关键跳.png

三、写注册机

python实现

#-*- coding: utf-8 -*-
list = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMTVMPROTECT310"
name = raw_input("Please input username: ")
password = ""
for i in range(len(name)):
    num = ord(name[(i+1)%len(name)]) >> 2
    num = num | (0x4*int(hex(ord(name[i])[-1])))
    num = num ^ 0x15
    password += list[num]
print "Password is: ",password
注册机python.png
通过.png

C++实现(还没调试好,不建议使用)

#include<iostream>
#include<string>
using namespace std;

int strToHex(char *ch, char *hex);
int hexToStr(char *hex, char *ch);
int hexCharToValue(const char ch);
char valueToHexCh(const int value);

int main()
{
    char s[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMTVMPROTECT310";
    int i,len;

    char ch[1024];
    char hex[1024];
    char result[1024];
    char strin,*str=hex;
    char *p_ch = ch;
    char *p_hex = hex;
    char *p_result = result;

    while (true)
    {
        cout << "Please input username: " << endl;
        cin >> str;
        len = strlen(str);
        cout << s[5];
        cout << "Password is: ";
        for (i = 0; i < len; i++)
        {
            *p_ch = str[(i + 1) % len];
            strToHex(p_ch, p_hex);
            strin =  *p_hex >> 2;
            strin = (strin | (0x4 * hexCharToValue(str[i]))) ^ 0x15;
            cout << s[strin];
        }
        cout << endl;
    }
}

int strToHex(char *ch, char *hex)
{
    int high, low;
    int tmp = 0;
    if (ch == NULL || hex == NULL) {
        return -1;
    }

    if (strlen(ch) == 0) {
        return -2;
    }

    while (*ch) {
        tmp = (int)*ch;
        high = tmp >> 4;
        low = tmp & 15;
        *hex++ = valueToHexCh(high); 
        *hex++ = valueToHexCh(low); 
        ch++;
    }
    *hex = '\0';
    return 0;
}

int hexToStr(char *hex, char *ch)
{
    int high, low;
    int tmp = 0;
    if (hex == NULL || ch == NULL) {
        return -1;
    }

    if (strlen(hex) % 2 == 1) {
        return -2;
    }

    while (*hex) {
        high = hexCharToValue(*hex);
        if (high < 0) {
            *ch = '\0';
            return -3;
        }
        hex++; 
        low = hexCharToValue(*hex);
        if (low < 0) {
            *ch = '\0';
            return -3;
        }
        tmp = (high << 4) + low;
        *ch++ = (char)tmp;
        hex++;
    }
    *ch = '\0';
    return 0;
}

int hexCharToValue(const char ch) {
    int result = 0;
    if (ch >= '0' && ch <= '9') {
        result = (int)(ch - '0');
    }
    else if (ch >= 'a' && ch <= 'z') {
        result = (int)(ch - 'a') + 10;
    }
    else if (ch >= 'A' && ch <= 'Z') {
        result = (int)(ch - 'A') + 10;
    }
    else {
        result = -1;
    }
    return result;
}

char valueToHexCh(const int value)
{
    char result = '\0';
    if (value >= 0 && value <= 9) {
        result = (char)(value + 48); 
    }
    else if (value >= 10 && value <= 15) {
        result = (char)(value - 10 + 65); 
    }
    else {
        ;
    }

    return result;
}

四、总结

​ 解这题应该可以直接patch,hook出00405E92的密码,或者可以直接改程序流,在关键跳那里nop,可惜时间不够。最近在学安卓逆向,很久没调OD了有点吃力。还是渣渣,要好好学习。

上一篇下一篇

猜你喜欢

热点阅读