Restore a certain weather sign algorithm with IDA operation guide

?The temperature dropped sharply, and it has been raining in the past few days. The VIP pop-up window that popped up in the weather software was very interesting, so I wanted to analyze it.

This article is only for learning and communication. If there is any infringement, please contact us and delete it.

Tools ida frida Android12 so=>arm64-v8a

1. Page display

What is analyzed is the sign under this page.

To locate the function entrance, first directly find the dynamically registered function, and then hook it

function Digest() {
    Java.perform(function () {
        let Digest = Java.use("com.moji.mjweather.library.Digest");
        Digest["nativeEncodeParams"].implementation = function (str) {
            console.log(`Digest.nativeEncodeParams is called: str=${str}`);
            let result = this["nativeEncodeParams"](str);
            console.log(`Digest.nativeEncodeParams result=${result}`);
            console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
            return result;
        };
    });
}

The result is as follows. I won’t guess what encryption it is this time. Go to 0x3d1a0 to see it step by step.

2. Function analysis

I saw a familiar operation here at 0x3d1a0. Many hash functions will have this operation.

Use ida’s own plug-in signsrch to take a look.

Chasing up is 0x15c04

Now that we’re here, let’s take a look at the implementation function of md5

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

typedef unsigned char *POINTER;

typedef struct {
    unsigned int state[4];
    unsigned int count[2];
    unsigned char buffer[64];
} MD5_CTX;

void MD5Init(MD5_CTX *);
void MD5Update(MD5_CTX *, unsigned char *, unsigned int);
void MD5Final(unsigned char[16], MD5_CTX *);
void MD5Transform(unsigned int[4], unsigned char[64]);
void Encode(unsigned char *, unsigned int *, unsigned int);
void Decode(unsigned int *, unsigned char *, unsigned int);

#define S11 7
#define S12 12
#define S13 17
#define S14 22

#define S21 5
#define S22 9
#define S23 14
#define S24 20

#define S31 4
#define S32 11
#define S33 16
#define S34 23

#define S41 6
#define S42 10
#define S43 15
#define S44 21



unsigned char PADDING[64] = {
    0x80, 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, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};



#define F(x, y, z) (((x) & amp; (y)) | ((~x) & amp; (z)))
#define G(x, y, z) (((x) & amp; (z)) | ((y) & amp; (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))



#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))

#define FF(a, b, c, d, x, s, ac) \
    {\
        (a) + = F((b), (c), (d)) + (x) + (unsigned int)(ac); \
        (a) = ROTATE_LEFT((a), (s)); \
        (a) + = (b); \
    }
#define GG(a, b, c, d, x, s, ac) \
    {\
        (a) + = G((b), (c), (d)) + (x) + (unsigned int)(ac); \
        (a) = ROTATE_LEFT((a), (s)); \
        (a) + = (b); \
    }
#define HH(a, b, c, d, x, s, ac) \
    { \
        (a) + = H((b), (c), (d)) + (x) + (unsigned int)(ac); \
        (a) = ROTATE_LEFT((a), (s)); \
        (a) + = (b); \
    }
#define II(a, b, c, d, x, s, ac) \
    {\
        (a) + = I((b), (c), (d)) + (x) + (unsigned int)(ac); \
        (a) = ROTATE_LEFT((a), (s)); \
        (a) + = (b); \
    }

void MD5Init(MD5_CTX *context)
{
    context->count[0] = context->count[1] = 0;
    context->state[0] = 0x67452301;
    context->state[1] = 0xefcdab89;
    context->state[2] = 0x98badcfe;
    context->state[3] = 0x10325476;
}

void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputLen)
{
    unsigned int i, index, partLen;
    index = (unsigned int)((context->count[0] >> 3) & amp; 0x3F);
    if ((context->count[0] + = ((unsigned int)inputLen << 3)) < ((unsigned int)inputLen << 3))
        context->count[1] + + ;
    context->count[1] + = ((unsigned int)inputLen >> 29);
    partLen = 64 - index;

    if (inputLen >= partLen) {
        memcpy( & amp;context->buffer[index], input, partLen);
        MD5Transform(context->state, context->buffer);
        for (i = partLen; i + 63 < inputLen; i + = 64) {
            MD5Transform(context->state, & amp;input[i]);
        }
        index = 0;
    } else {
        i = 0;
    }
    memcpy( & amp;context->buffer[index], & amp;input[i], inputLen - i);
}

void MD5Final(unsigned char digest[16], MD5_CTX *context)
{
    unsigned char bits[8];
    unsigned int index, padLen;
    Encode(bits, context->count, 8);
    index = (unsigned int)((context->count[0] >> 3) & amp; 0x3f);
    padLen = (index < 56) ? (56 - index) : (120 - index);
    MD5Update(context, PADDING, padLen);
    MD5Update(context, bits, 8);
    Encode(digest, context->state, 16);
    memset(context, 0, sizeof(*context));
}

void MD5Transform(unsigned int state[4], unsigned char block[64])
{
    unsigned int a = state[0], b = state[1], c = state[2], d = state[3], x[16];
    Decode(x, block, 64);

    FF(a, b, c, d, x[0], S11, 0xd76aa478);
    FF(d, a, b, c, x[1], S12, 0xe8c7b756);
    FF(c, d, a, b, x[2], S13, 0x242070db);
    FF(b, c, d, a, x[3], S14, 0xc1bdceee);

    FF(a, b, c, d, x[4], S11, 0xf57c0faf);
    FF(d, a, b, c, x[5], S12, 0x4787c62a);
    FF(c, d, a, b, x[6], S13, 0xa8304613);
    FF(b, c, d, a, x[7], S14, 0xfd469501);

    FF(a, b, c, d, x[8], S11, 0x698098d8);
    FF(d, a, b, c, x[9], S12, 0x8b44f7af);
    FF(c, d, a, b, x[10], S13, 0xffff5bb1);
    FF(b, c, d, a, x[11], S14, 0x895cd7be);

    FF(a, b, c, d, x[12], S11, 0x6b901122);
    FF(d, a, b, c, x[13], S12, 0xfd987193);
    FF(c, d, a, b, x[14], S13, 0xa679438e);
    FF(b, c, d, a, x[15], S14, 0x49b40821);

    GG(a, b, c, d, x[1], S21, 0xf61e2562);
    GG(d, a, b, c, x[6], S22, 0xc040b340);
    GG(c, d, a, b, x[11], S23, 0x265e5a51);
    GG(b, c, d, a, x[0], S24, 0xe9b6c7aa);
    GG(a, b, c, d, x[5], S21, 0xd62f105d);
    GG(d, a, b, c, x[10], S22, 0x2441453);
    GG(c, d, a, b, x[15], S23, 0xd8a1e681);
    GG(b, c, d, a, x[4], S24, 0xe7d3fbc8);
    GG(a, b, c, d, x[9], S21, 0x21e1cde6);
    GG(d, a, b, c, x[14], S22, 0xc33707d6);
    GG(c, d, a, b, x[3], S23, 0xf4d50d87);
    GG(b, c, d, a, x[8], S24, 0x455a14ed);
    GG(a, b, c, d, x[13], S21, 0xa9e3e905);
    GG(d, a, b, c, x[2], S22, 0xfcefa3f8);
    GG(c, d, a, b, x[7], S23, 0x676f02d9);
    GG(b, c, d, a, x[12], S24, 0x8d2a4c8a);
    HH(a, b, c, d, x[5], S31, 0xfffa3942);
    HH(d, a, b, c, x[8], S32, 0x8771f681);
    HH(c, d, a, b, x[11], S33, 0x6d9d6122);
    HH(b, c, d, a, x[14], S34, 0xfde5380c);
    HH(a, b, c, d, x[1], S31, 0xa4beea44);
    HH(d, a, b, c, x[4], S32, 0x4bdecfa9);
    HH(c, d, a, b, x[7], S33, 0xf6bb4b60);
    HH(b, c, d, a, x[10], S34, 0xbebfbc70);
    HH(a, b, c, d, x[13], S31, 0x289b7ec6);
    HH(d, a, b, c, x[0], S32, 0xeaa127fa);
    HH(c, d, a, b, x[3], S33, 0xd4ef3085);
    HH(b, c, d, a, x[6], S34, 0x4881d05);
    HH(a, b, c, d, x[9], S31, 0xd9d4d039);
    HH(d, a, b, c, x[12], S32, 0xe6db99e5);
    HH(c, d, a, b, x[15], S33, 0x1fa27cf8);
    HH(b, c, d, a, x[2], S34, 0xc4ac5665);
    II(a, b, c, d, x[0], S41, 0xf4292244);
    II(d, a, b, c, x[7], S42, 0x432aff97);
    II(c, d, a, b, x[14], S43, 0xab9423a7);
    II(b, c, d, a, x[5], S44, 0xfc93a039);
    II(a, b, c, d, x[12], S41, 0x655b59c3);
    II(d, a, b, c, x[3], S42, 0x8f0ccc92);
    II(c, d, a, b, x[10], S43, 0xffeff47d);
    II(b, c, d, a, x[1], S44, 0x85845dd1);
    II(a, b, c, d, x[8], S41, 0x6fa87e4f);
    II(d, a, b, c, x[15], S42, 0xfe2ce6e0);
    II(c, d, a, b, x[6], S43, 0xa3014314);
    II(b, c, d, a, x[13], S44, 0x4e0811a1);
    II(a, b, c, d, x[4], S41, 0xf7537e82);
    II(d, a, b, c, x[11], S42, 0xbd3af235);
    II(c, d, a, b, x[2], S43, 0x2ad7d2bb);
    II(b, c, d, a, x[9], S44, 0xeb86d391);

    state[0] + = a;
    state[1] + = b;
    state[2] + = c;
    state[3] + = d;
}

void Encode(unsigned char *output, unsigned int *input, unsigned int len)
{
    unsigned int i, j;

    for (i = 0, j = 0; j < len; i + + , j + = 4)
    {
        output[j] = (unsigned char)(input[i] & amp; 0xff);
        output[j + 1] = (unsigned char)((input[i] >> 8) & amp; 0xff);
        output[j + 2] = (unsigned char)((input[i] >> 16) & amp; 0xff);
        output[j + 3] = (unsigned char)((input[i] >> 24) & amp; 0xff);
    }
}

void Decode(unsigned int *output, unsigned char *input, unsigned int len)
{
    unsigned int i, j;

    for (i = 0, j = 0; j < len; i + + , j + = 4)
        output[i] = ((unsigned int)input[j]) | (((unsigned int)input[j + 1]) << 8) |
                    (((unsigned int)input[j + 2]) << 16) | (((unsigned int)input[j + 3]) << 24);
}

int main()
{
    MD5_CTX md5_calc;
    char c[]="123";
    unsigned char md5[16];
    MD5Init( & amp;md5_calc);
    MD5Update( & amp;md5_calc, (unsigned char *)c, strlen(c));
    MD5Final(md5, & amp;md5_calc);
    printf("result=> ");
    for (int i = 0; i < 16; i + + )
        printf(" x", md5[i]);
    printf("\
");
    return 0;
}

The hash operation has three MD5Update operations

Go to sub_14E14 and see if anything has been changed.

Here is a small operation, you can use invert sign to see the complement code

So the results are normal

Let’s take a look at sub_14DF0

32-bit data does not change from the high position to the high position.

So I calculated the results, and they don’t seem to match up.

If you hook these functions, you will find the problem.

 v18 = sub_14DF0(v28); // MD5Init</code><code> sub_1952C(v18);</code><code> sub_14E14(v28, v16, v17); // MD5Update</code><code> sub_15C04(v28, v31); // MD5Final

The result will be correct after processing

3. An illustrated IDA guide

https://bbs.kanxue.com/thread-266021.htm

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Algorithm skill tree Home page Overview 56321 people are learning the system