Switch to Maven to build the Java bits.

Maven is now used to update the constants, build the Java code, call make to
build the native library, and run all the tests. I have removed the "install"
and "uninstall" targets; instead, the expectation will be that the JNI library
will be placed somewhere on java.library.path and the JAR file will be used as
usual (e.g. in a downstream Maven project, or placed on the classpath of your
project).

Since Maven is now running our tests, this eliminates the need to bundle test
dependencies in `testdep`, and makes the project structured more like a typical
Java project.
This commit is contained in:
Robert Xiao
2023-06-29 16:04:51 -07:00
parent 2198ea4f69
commit dfdc8e7e8e
69 changed files with 155 additions and 100 deletions

1
.gitignore vendored
View File

@@ -45,7 +45,6 @@ _*.txt
_*.diff _*.diff
tmp/ tmp/
bindings/java/unicorn_Unicorn.h
bindings/python/build/ bindings/python/build/
bindings/python/dist/ bindings/python/dist/
bindings/python/src/ bindings/python/src/

View File

@@ -73,7 +73,7 @@ template = {
'header': "// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT\n\npackage unicorn;\n\npublic interface %sConst {\n", 'header': "// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT\n\npackage unicorn;\n\npublic interface %sConst {\n",
'footer': "\n}\n", 'footer': "\n}\n",
'line_format': ' public static final int UC_%s = %s;\n', 'line_format': ' public static final int UC_%s = %s;\n',
'out_file': './java/unicorn/%sConst.java', 'out_file': './java/src/main/java/unicorn/%sConst.java',
# prefixes for constant filenames of all archs - case sensitive # prefixes for constant filenames of all archs - case sensitive
'arm.h': 'Arm', 'arm.h': 'Arm',
'arm64.h': 'Arm64', 'arm64.h': 'Arm64',

2
bindings/java/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
target/
unicorn_Unicorn.h

View File

@@ -1,18 +1,14 @@
all: jar lib samples # Makefile for the native JNI library. Automatically called by Maven.
JC=javac JAVA_HOME ?= $(shell java -XshowSettings:properties -version 2>&1 | sed -n 's/ *java.home = //p')
JAVA_HOME := $(shell readlink -f `which $(JC)` | sed "s:/bin/$(JC)::") ifeq ($(JAVA_HOME),)
$(error JAVA_HOME could not be determined; please set it manually (make JAVA_HOME=...))
JAVA_INC := $(shell realpath $(JAVA_HOME)/include) endif
JAVA_INC := $(JAVA_HOME)/include
JAVA_PLATFORM_INC := $(shell dirname `find $(JAVA_INC) -name jni_md.h`) JAVA_PLATFORM_INC := $(shell dirname `find $(JAVA_INC) -name jni_md.h`)
UNICORN_INC := ../../include
UNICORN_INC=../../include
SAMPLES := $(shell ls samples/*.java)
TESTS := $(shell ls tests/*.java)
SRC := $(shell ls unicorn/*.java)
OS := $(shell uname) OS := $(shell uname)
ifeq ($(OS),Darwin) ifeq ($(OS),Darwin)
@@ -23,67 +19,29 @@ else
LIB_EXT=.dll LIB_EXT=.dll
endif endif
all: libunicorn_java$(LIB_EXT)
CC=gcc CC=gcc
CFLAGS=-fPIC CFLAGS=-fPIC
LDFLAGS=-shared -fPIC LDFLAGS=-shared -fPIC
LIBS=-lunicorn # May also use -lunicorn to dynamically link against the installed unicorn
LIBDIR=-L../../ LIBS=../../build/libunicorn.a
INCS=-I$(JAVA_INC) -I$(JAVA_PLATFORM_INC) -I$(UNICORN_INC) INCS=-I$(JAVA_INC) -I$(JAVA_PLATFORM_INC) -I$(UNICORN_INC)
CLASSPATH=./
.SUFFIXES: .java .class
tests/%.class: tests/%.java
$(JC) -Xlint:deprecation -classpath .:unicorn.jar:testdep/junit-4.13.2.jar $(JFLAGS) $<
%.class: %.java
$(JC) -Xlint:deprecation -classpath .:unicorn.jar $(JFLAGS) $<
OBJS=unicorn_Unicorn.o OBJS=unicorn_Unicorn.o
JARFILE=unicorn.jar unicorn_Unicorn.h: src/main/java/unicorn/Unicorn.java
javah -cp src/main/java -o $@ unicorn.Unicorn
%.o: %.c
$(CC) -c $(CFLAGS) $(INCS) $< -o $@
unicorn_Unicorn.h: unicorn/Unicorn.java
$(JC) -h . $<
unicorn_Unicorn.o: unicorn_Unicorn.c unicorn_Unicorn.h unicorn_Unicorn.o: unicorn_Unicorn.c unicorn_Unicorn.h
$(CC) -O2 -Wall -Wextra -Wno-unused-parameter -c $(CFLAGS) $(INCS) $< -o $@ $(CC) -O2 -Wall -Wextra -Wno-unused-parameter -c $(CFLAGS) $(INCS) $< -o $@
libunicorn_java$(LIB_EXT): unicorn_Unicorn.o libunicorn_java$(LIB_EXT): $(OBJS)
$(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
lib: libunicorn_java$(LIB_EXT) unicorn_Unicorn.h
$(CC) -o $< $(LDFLAGS) $(OBJS) $(LIBDIR) $(LIBS)
samples: $(SAMPLES:.java=.class)
tests: $(TESTS:.java=.class)
jarfiles: $(SRC:.java=.class)
jar: jarfiles
jar cf $(JARFILE) unicorn/*.class
test: lib samples tests
java -Xcheck:jni -cp .:testdep/hamcrest-2.2.jar:testdep/junit-4.13.2.jar org.junit.runner.JUnitCore $(subst /,.,$(TESTS:.java=))
install: lib jar
cp libunicorn_java$(LIB_EXT) /usr/lib
cp $(JARFILE) /usr/share/java
uninstall:
rm -f /usr/lib/libunicorn_java$(LIB_EXT)
rm -f /usr/share/java/$(JARFILE)
gen_const:
cd .. && python3 const_generator.py java
clean: clean:
rm -f unicorn/*.class rm -f libunicorn_java$(LIB_EXT)
rm -f samples/*.class rm -f unicorn_Unicorn.h
rm -f *.so rm -f $(OBJS)
rm -f *.dylib
rm -f *.dll
.PHONY: all lib samples jar install uninstall gen_const clean .PHONY: all clean

View File

@@ -1,37 +0,0 @@
This documentation explains how to install the Java binding for Unicorn
from source.
0. Install the core engine as dependency
Follow README in the root directory to compile & install the core.
On *nix, this can simply done by:
$ sudo ./make.sh install
1. Install a JDK for your platform. When done, make sure the JDK tools
are in your PATH.
2. Change directories into the java bindings, build and install
$ cd bindings/java
$ make
$ sudo make install
$ make samples
The samples directory contains some sample code to show how to use Unicorn API.
- Sample_<arch>.java
These show how to access architecture-specific information for each
architecture.
- Shellcode.java
This shows how to analyze a Linux shellcode.
- SampleNetworkAuditing.java
Unicorn sample for auditing network connection and file handling in shellcode.
To uninstall Java binding for Unicorn:
$ sudo make uninstall

39
bindings/java/README.md Normal file
View File

@@ -0,0 +1,39 @@
This documentation explains how to install the Java binding for Unicorn
from source.
0. Follow `docs/COMPILE.md` in the root directory to compile the core to the `build` directory.
Note: by default, the Java binding native library will be built by statically linking to
`../../build/libunicorn.a`, thereby removing `libunicorn` as a runtime dependency, but
making the produced native library `libunicorn_java` bigger.
If you instead want to dynamically link against the installed `libunicorn`, change
`LIBS=../../build/libunicorn.a` to `LIBS=-lunicorn` in `Makefile`.
1. Install a JDK for your platform.
2. Install Maven: https://maven.apache.org/install.html.
3. Change directories into the java bindings and build the Maven package:
$ mvn package
This will automatically build and test the Unicorn Java bindings.
The bindings consist of the native JNI library (`libunicorn_java.{so,dylib,dll}`)
and the Java JAR (`target/unicorn-2.xx.jar`). You will need to have the native
library on `java.library.path` and the JAR on your classpath.
The `src/main/test/java` directory contains some sample code to show how to use Unicorn API.
`samples` is a set of sample classes showcasing the various features of the Unicorn API,
while `tests` is a set of JUnit tests for the API.
- `Sample_<arch>.java`:
These show how to access architecture-specific information for each
architecture.
- `Shellcode.java`:
This shows how to analyze a Linux shellcode.
- `SampleNetworkAuditing.java`:
Unicorn sample for auditing network connection and file handling in shellcode.

92
bindings/java/pom.xml Normal file
View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.unicorn-engine</groupId>
<artifactId>unicorn</artifactId>
<version>2.0</version>
<name>unicorn</name>
<url>https://www.unicorn-engine.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>generate-consts</id>
<phase>generate-sources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>python3</executable>
<arguments>
<argument>const_generator.py</argument>
<argument>java</argument>
</arguments>
<workingDirectory>${project.basedir}/..</workingDirectory>
</configuration>
</execution>
<execution>
<id>compile-jni-lib</id>
<phase>compile</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>make</executable>
<arguments>
<argument>JAVA_HOME=${java.home}</argument>
<argument>all</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>clean-jni-lib</id>
<phase>clean</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>make</executable>
<arguments>
<argument>clean</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -77,6 +77,7 @@ public interface UnicornConst {
public static final int UC_ERR_HOOK_EXIST = 19; public static final int UC_ERR_HOOK_EXIST = 19;
public static final int UC_ERR_RESOURCE = 20; public static final int UC_ERR_RESOURCE = 20;
public static final int UC_ERR_EXCEPTION = 21; public static final int UC_ERR_EXCEPTION = 21;
public static final int UC_ERR_OVERFLOW = 22;
public static final int UC_MEM_READ = 16; public static final int UC_MEM_READ = 16;
public static final int UC_MEM_WRITE = 17; public static final int UC_MEM_WRITE = 17;
public static final int UC_MEM_FETCH = 18; public static final int UC_MEM_FETCH = 18;
@@ -142,6 +143,7 @@ public interface UnicornConst {
public static final int UC_CTL_TB_FLUSH = 10; public static final int UC_CTL_TB_FLUSH = 10;
public static final int UC_CTL_TLB_FLUSH = 11; public static final int UC_CTL_TLB_FLUSH = 11;
public static final int UC_CTL_TLB_TYPE = 12; public static final int UC_CTL_TLB_TYPE = 12;
public static final int UC_CTL_TCG_BUFFER_SIZE = 13;
public static final int UC_PROT_NONE = 0; public static final int UC_PROT_NONE = 0;
public static final int UC_PROT_READ = 1; public static final int UC_PROT_READ = 1;