Files
unicorn/bindings/java/tests/HookTests.java
Robert Xiao 4f563490e2 Update Java samples to match C samples.
Also add all of the samples as Java tests, referencing the output of the C
samples.
2023-06-17 14:19:10 -07:00

126 lines
4.8 KiB
Java

package tests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import org.junit.Test;
import unicorn.CodeHook;
import unicorn.EdgeGeneratedHook;
import unicorn.TlbFillHook;
import unicorn.TranslationBlock;
import unicorn.Unicorn;
import unicorn.UnicornException;
public class HookTests {
private static void assertTranslationBlock(TranslationBlock expected,
TranslationBlock actual) {
assertEquals(expected.pc, actual.pc);
assertEquals(expected.icount, actual.icount);
assertEquals(expected.size, actual.size);
}
@Test
public void testEdgeHook() {
/*
00000000 83FB01 cmp ebx,byte +0x1
00000003 7405 jz 0xa
00000005 B802000000 mov eax,0x2
0000000A 40 inc eax
0000000B EBFE jmp short 0xb
*/
final byte[] X86_CODE =
{ -125, -5, 1, 116, 5, -72, 2, 0, 0, 0, 64, -21, -2 };
final TranslationBlock[] expectedTb = { null, null };
long ADDRESS = 0x100000;
Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32);
u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL);
u.mem_write(ADDRESS, X86_CODE);
expectedTb[1] = new TranslationBlock(ADDRESS, 2, 5);
u.hook_add((EdgeGeneratedHook) (uc, cur_tb, prev_tb, user) -> {
assertTranslationBlock(expectedTb[0], cur_tb);
assertTranslationBlock(expectedTb[1], prev_tb);
assertEquals("user data", user);
}, ADDRESS, ADDRESS + 10, "user data");
// TODO(nneonneo): why is icount 2/3 in the subsequent blocks?
expectedTb[0] = new TranslationBlock(ADDRESS + 10, 2, 1);
u.reg_write(Unicorn.UC_X86_REG_EBX, 1);
u.emu_start(ADDRESS, ADDRESS + 11, 0, 0);
expectedTb[0] = new TranslationBlock(ADDRESS + 5, 3, 6);
u.reg_write(Unicorn.UC_X86_REG_EBX, 0);
u.emu_start(ADDRESS, ADDRESS + 11, 0, 0);
assertTranslationBlock(new TranslationBlock(ADDRESS, 2, 5),
u.ctl_request_cache(ADDRESS));
// TODO(nneonneo): I don't totally understand this output! Why 8 bytes at address 5?
assertTranslationBlock(new TranslationBlock(ADDRESS + 5, 3, 8),
u.ctl_request_cache(ADDRESS + 5));
}
@Test
public void testTlbHook() {
// mov ecx, [0xaaaaaaa8]
final byte[] X86_CODE32_MEM_READ = { -117, 13, -88, -86, -86, -86 };
long ADDRESS = 0x100000;
Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32);
u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL);
u.mem_map(0xbbbbb000L, 0x1000, Unicorn.UC_PROT_READ);
u.hook_add((TlbFillHook) (uc, address, type, user_data) -> {
assertEquals("fill hook address", 0xaaaaa000L, address);
assertEquals("fill hook type", Unicorn.UC_MEM_READ, type);
assertEquals("fill hook user", "fill_hook", user_data);
return 0xbbbbb000L | Unicorn.UC_PROT_READ;
}, 0xaaaaa000L, 0xaaaab000L, "fill_hook");
u.mem_write(ADDRESS, X86_CODE32_MEM_READ);
u.mem_write(0xbbbbbaa8L, new byte[] { 1, 2, 3, 4 });
u.reg_write(Unicorn.UC_X86_REG_ECX, 0x12345678);
u.ctl_tlb_mode(Unicorn.UC_TLB_VIRTUAL);
u.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_READ.length, 0, 0);
assertEquals("ecx", u.reg_read(Unicorn.UC_X86_REG_ECX), 0x04030201);
}
@Test
public void testRemoveHook() {
byte[] X86_CODE = { 0x40, 0x40, 0x40, 0x40 }; // (inc eax) x 4
int ADDRESS = 0x10000;
final int[] hook_accum = { 0 };
Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32);
u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL);
u.mem_write(ADDRESS, X86_CODE);
CodeHook hook =
(uc, address, size, user) -> hook_accum[0] += (int) user;
long h1 = u.hook_add(hook, ADDRESS, ADDRESS, 1);
long h2 = u.hook_add(hook, ADDRESS + 1, ADDRESS + 1, 2);
long h3 = u.hook_add(hook, ADDRESS + 2, ADDRESS + 2, 4);
long h4 = u.hook_add(hook, ADDRESS + 3, ADDRESS + 3, 8);
hook_accum[0] = 0;
u.emu_start(ADDRESS, ADDRESS + X86_CODE.length, 0, 0);
assertEquals(15, hook_accum[0]);
u.hook_del(h2);
hook_accum[0] = 0;
u.emu_start(ADDRESS, ADDRESS + X86_CODE.length, 0, 0);
assertEquals(13, hook_accum[0]);
u.hook_del(hook);
hook_accum[0] = 0;
u.emu_start(ADDRESS, ADDRESS + X86_CODE.length, 0, 0);
assertEquals(0, hook_accum[0]);
assertThrows(UnicornException.class, () -> u.hook_del(h1));
assertThrows(UnicornException.class, () -> u.hook_del(h3));
assertThrows(UnicornException.class, () -> u.hook_del(h4));
}
}