sougou search app weixin official account list so encryption algorithm analysis reduction RSA encryption Base64 analysis

Keywords: Algorithm

For study and research only. Please do not use it for illegal purposes. I will not bear any legal responsibility.

Recommended reading

Using unidbg hook inline hook
Using unidbg console debugger
sougou search app weixin official account list so encryption algorithm analysis of reduction analysis simple analysis
sougou search app weixin official account list so encryption algorithm analysis reduction zip encryption AES analysis
sougou search app weixin official account list so encryption algorithm analysis of reduction response content decryption analysis

const Longge = Function() {}

const a = omnipotent silly treasure, who shares various operations in a different posture every day. He has been sharing cryptography in recent October;
const b = Click join planet;
return "invincible dragon brother";

preface

If you want to learn the restoration of unidbg android reverse cryptography algorithm, you can call Longge ();
Then the last article analyzes the encryption logic of rsa base64

0x1

The last article analyzed the static registration logic of so


That's right here. Click in

There are five parameters in total. The first two are default, namely jnienv, jobject or jclass. The last three are passed in
The above is done with some string initialization and called j_. Sc_ Encryptwallencode function, click to see

After entering, there are three functions that need our attention. The first two are not very important after analysis. We mainly analyze the last one


Thanks for not removing the code symbols, you can see the dense algorithms inside

In the next analysis, we can see that we are familiar with the string. Isn't it the request parameter of the previous request package? Here is the encryption logic of all algorithms

0x2

There are many algorithms inside. Let's analyze rsa and base64 this time

rsa


The previous are some conventional judgment assignment operations

v10 = operator new(48u);
This line is to create a memory with a size of 48 bytes, and v10 only has the memory address

EncryptWall::WallKey::WallKey(v10);
Here, call a function to enter the memory address and click to see it

EncryptWall::WallKey::WallKey


The click in logic is also relatively simple. The two do while loops a total of 48 times, just filling in the space of 48 bytes of memory

lrand48() function under linux
Randomly generate long integers between 0 - 2 ^ 31

Tips: continue down

v12 = RSA_Encrypt(v10 + 16, 32u, &v60, &v59);
Here is to call the rsa encryption function. The four parameters are the first address of v10 plus 16 and 32 numbers, the address of v60 and the address of v59

RSA_Encrypt

n_crypto::SetSignPubKey
Here is to generate public_key, module and index are passed in

n_crypto::PublicEnc(v8, v9, v6, &v11, v4);
Call this function to start encryption. There are five parameters in total
They are 1:32 byte address, 2:32 number, 3:128 byte memory, 4: memory address and 5:80 byte memory address

Tips: end of RSA analysis

base64Encode


Here is the encryption result of rsa. Here is another layer of base64 coding. You can verify whether it is standard base64 later

0x3

The algorithm analysis is almost complete. Use the console debugger and hook functions of unidbg to verify the data. Those unfamiliar with it can see the above recommended articles

unidbg unicorn inline hook

First, use the EncryptWall::WallKey::WallKey function to see what data is generated

public void hookUnicornWallKey() {
	emulator.getBackend().hook_add_new(new CodeHook() {
		@Override
		public void onAttach(Unicorn.UnHook unHook) {
		}

		@Override
		public void detach() {
		}

		@Override
		public void hook(Backend backend, long address, int size, Object user) {
			if (address == (module.base + 0xB332)) {
				System.out.println("Hook By Unicorn hookUnicornWallKey");
				RegisterContext ctx = emulator.getContext();
				Pointer input1 = ctx.getPointerArg(0);
				Inspector.inspect(input1.getByteArray(0, 0x100), " Parameter 1");
			}
			if (address == (module.base + 0xB336)) {
				RegisterContext ctx = emulator.getContext();
				Inspector.inspect(ctx.getPointerArg(0).getByteArray(0, 0x100), " Unicorn hook hookUnicornWallKey");
			}
		}
	}, module.base + 0xB332, module.base + 0xB336, null);
}


As you can see from the running result, it is just 48 bytes of data

Then hook rsa base64 function respectively

public void hookUnicornRsa() {
	emulator.getBackend().hook_add_new(new CodeHook() {
		@Override
		public void onAttach(Unicorn.UnHook unHook) {
		}

		@Override
		public void detach() {
		}

		@Override
		public void hook(Backend backend, long address, int size, Object user) {
			if (address == (module.base + 0xB34E)) {
				RegisterContext ctx = emulator.getContext();
				Pointer input1 = ctx.getPointerArg(0);
				Inspector.inspect(input1.getByteArray(0, 0x100), " hookUnicornRsa Parameter 1");
			}
			if (address == (module.base + 0xB352)) {
				RegisterContext ctx = emulator.getContext();
				Inspector.inspect(ctx.getPointerArg(0).getByteArray(0, 0x100), " Unicorn hook hookUnicornRsa");
			}
		}
	}, module.base + 0xB34E, module.base + 0xB352, null);
}

public void hookUnicornBase64Encode() {
	emulator.getBackend().hook_add_new(new CodeHook() {
		@Override
		public void onAttach(Unicorn.UnHook unHook) {
		}

		@Override
		public void detach() {
		}

		@Override
		public void hook(Backend backend, long address, int size, Object user) {
			if (address == (module.base + 0xB372)) {
				RegisterContext ctx = emulator.getContext();
				Pointer input1 = ctx.getPointerArg(0);
				Inspector.inspect(input1.getByteArray(0, 0x100), " hookUnicornBase64Encode Parameter 1");
			}
			if (address == (module.base + 0xB376)) {
				RegisterContext ctx = emulator.getContext();
				Inspector.inspect(ctx.getPointerArg(0).getByteArray(0, 0x100), " Unicorn hook hookUnicornBase64Encode");
			}
		}
	}, module.base + 0xB372, module.base + 0xB376, null);
}

Run after writing the code

The first parameter of rsa is 32 bytes, that is, the last 32 bytes of 48 bytes of data randomly generated before, and the return value is 128 bytes

The first parameter of base64 is just the return value of the previous rsa

Use CyberChef website to verify whether it is a standard base64. The result is, as expected, the target

last

rsa base64 is finished. The next article will analyze the zip + aes algorithm

More wonderful content, source file download, original link, blogger's personal website: https://www.qinless.com/485

Posted by new7media on Sun, 24 Oct 2021 19:52:27 -0700