diff --git a/.github/workflows/Crate-publishing.yml b/.github/workflows/Crate-publishing.yml new file mode 100644 index 00000000..fcd5552b --- /dev/null +++ b/.github/workflows/Crate-publishing.yml @@ -0,0 +1,93 @@ +name: Crate 📦 Distribution + +on: + push: + paths-ignore: + - ".gitignore" + - "docs/**" + - "README" + - "CREDITS.TXT" + - "COPYING_GLIB" + - "COPYING.LGPL2" + - "AUTHORS.TXT" + - "CHANGELOG" + - "COPYING" + pull_request: + +env: + CI: true + +jobs: + build: + runs-on: ${{ matrix.config.os }} + name: ${{ matrix.config.name }} + strategy: + fail-fast: false + matrix: + config: + - { + os: windows-latest, + arch: x64, + name: 'Windows x86_64' + } + - { + os: windows-latest, + arch: x32, + name: 'Windows x86' + } + - { + os: ubuntu-latest, + arch: x64, + name: 'Ubuntu x86_64' + } + - { + os: macos-latest, + arch: x64, + name: 'macOS x86_64' + } + steps: + - uses: actions/checkout@v2 + + - name: '🛠️ Set up Rust' + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + default: true + + - name: '🛠️ Add msbuild to PATH' + if: contains(matrix.config.name, 'win') + uses: microsoft/setup-msbuild@v1.0.3 + with: + vs-version: '16.5' + + - name: '🛠️ Win build dependencies' + if: contains(matrix.config.name, 'win') + shell: bash + run: | + choco install ninja cmake + + - name: '🚧 Cargo test' + run: | + cd bindings/rust && cargo test + + # - name: '📤 Upload artifact' + # uses: actions/upload-artifact@v2 + # with: + # path: ${{ github.workspace }}/bindings/python/dist/* + + # publish: + # needs: [build] + # runs-on: ubuntu-latest + # if: startsWith(github.ref, 'refs/tags') + # steps: + # - uses: actions/download-artifact@v2 + # with: + # name: artifact + # path: dist + + # - name: '📦 Publish distribution to PyPI' + # uses: pypa/gh-action-pypi-publish@master + # with: + # user: __token__ + # password: ${{ secrets.pypi_pass }} diff --git a/.github/workflows/PyPI-publishing.yml b/.github/workflows/PyPI-publishing.yml index 76751f2b..81043388 100644 --- a/.github/workflows/PyPI-publishing.yml +++ b/.github/workflows/PyPI-publishing.yml @@ -3,7 +3,6 @@ name: PyPI 📦 Distribution on: push: paths-ignore: - - ".github/**" - ".gitignore" - "docs/**" - "README" diff --git a/.github/workflows/build-uc2.yml b/.github/workflows/build-uc2.yml index 93b871a6..61b45053 100644 --- a/.github/workflows/build-uc2.yml +++ b/.github/workflows/build-uc2.yml @@ -1,10 +1,8 @@ name: Build UC2 + on: push: - tags-ignore: - - "*" paths-ignore: - - ".github/**" - ".gitignore" - "docs/**" - "README" @@ -16,13 +14,14 @@ on: - "COPYING" pull_request: + env: CI: true jobs: Windows: runs-on: ${{ matrix.config.os }} - name: ${{ matrix.config.name }} - ${{ matrix.compiler }} + name: ${{ matrix.config.name }} strategy: fail-fast: false matrix: @@ -65,15 +64,22 @@ jobs: archiver: '7z a', generators: 'Visual Studio 16 2019' } + - { + os: windows-latest, + arch: x86, + python-arch: x86, + python-ver: '3.8', + name: 'windows-x86 MSVC 32bit', + msvc-arch: x86, + artifact: 'windows_msvc32.7z', + build_type: 'Debug', + archiver: '7z a', + generators: 'Visual Studio 16 2019' + } compiler: [ gcc ] steps: - uses: actions/checkout@v2 - # - name: '🛠️ Python setup' - # uses: actions/setup-python@v2 - # with: - # python-version: ${{ matrix.config.python-ver }} - - name: '🛠️ Win MINGW setup' if: contains(matrix.config.mingw, 'MINGW') uses: msys2/setup-msys2@v2 @@ -87,12 +93,12 @@ jobs: mingw-w64-${{ matrix.config.mingw-arch }}-${{ matrix.compiler }} mingw-w64-${{ matrix.config.mingw-arch }}-toolchain - - name: '🛠️ Win MSVC setup' - if: contains(matrix.config.name, 'MSVC') + - name: '🛠️ Win MSVC 64 setup' + if: contains(matrix.config.name, 'MSVC 64') uses: microsoft/setup-msbuild@v1 - - name: '🚧 Win MSVC build' - if: contains(matrix.config.name, 'MSVC') + - name: '🚧 Win MSVC 64 build' + if: contains(matrix.config.name, 'MSVC 64') shell: bash run: | choco install ninja cmake @@ -110,6 +116,32 @@ jobs: ctest -C ${{ matrix.config.build_type }} mv Debug instdir + - name: '🛠️ Win MSVC 32 setup' + if: contains(matrix.config.name, 'MSVC 32') + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x86 + + - name: '🚧 Win MSVC 32 build' + if: contains(matrix.config.name, 'MSVC 32') + shell: bash + run: | + choco install ninja cmake + ninja --version + cmake --version + mkdir build + cmake \ + -S . \ + -B . \ + -A "win32" \ + -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \ + -G "${{ matrix.config.generators }}" \ + -DCMAKE_INSTALL_PREFIX:PATH=instdir + cmake --build . --config ${{ matrix.config.build_type }} + cmake --install . --strip --config ${{ matrix.config.build_type }} + ctest -C ${{ matrix.config.build_type }} + mv Debug instdir + - name: '🚧 Win MINGW build' if: contains(matrix.config.mingw, 'MINGW') shell: msys2 {0} @@ -167,6 +199,17 @@ jobs: archiver: '7za a', generators: 'Ninja' } + - { + os: macos-11, + arch: x86_64, + python-arch: x86_64, + python-ver: '3.8', + name: 'android cmake', + artifact: 'Android-x86_64.7z', + build_type: 'Debug', + archiver: '7za a', + generators: 'Ninja' + } compiler: [ gcc ] steps: - uses: actions/checkout@v2 @@ -177,24 +220,81 @@ jobs: # python-version: ${{ matrix.config.python-ver }} - name: '🚧 Mac build' - if: contains(matrix.config.os, 'macos') + if: contains(matrix.config.name, 'macos-x64') shell: bash run: | - brew install p7zip cmake ninja - ninja --version - cmake --version - mkdir build - mkdir instdir - cmake \ - -S . \ - -B . \ - -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \ - -G "${{ matrix.config.generators }}" \ - -DCMAKE_INSTALL_PREFIX:PATH=instdir - cmake --build . --config ${{ matrix.config.build_type }} - cmake --install . --strip - ctest -C ${{ matrix.config.build_type }} - + brew install p7zip cmake ninja + ninja --version + cmake --version + mkdir build + mkdir instdir + cmake \ + -S . \ + -B . \ + -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \ + -G "${{ matrix.config.generators }}" \ + -DCMAKE_INSTALL_PREFIX:PATH=instdir + cmake --build . --config ${{ matrix.config.build_type }} + cmake --install . --strip + ctest -C ${{ matrix.config.build_type }} + + - name: '🚧 Android x86_64 build' + if: contains(matrix.config.name, 'android') + shell: bash + run: | + brew install p7zip cmake ninja + mkdir build + mkdir instdir + cmake . -DCMAKE_TOOLCHAIN_FILE="$ANDROID_HOME/ndk/21.4.7075529/build/cmake/android.toolchain.cmake" \ + -DANDROID_PLATFORM=android-28 \ + -DANDROID_NDK="$ANDROID_HOME/ndk/21.4.7075529" \ + -DANDROID_ABI=${{ matrix.config.arch }} \ + -DOLP_SDK_ENABLE_TESTING=NO \ + -DOLP_SDK_BUILD_EXAMPLES=ON \ + -S . \ + -B . \ + -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \ + -G "${{ matrix.config.generators }}" \ + -DCMAKE_INSTALL_PREFIX:PATH=instdir + cmake --build . --config ${{ matrix.config.build_type }} + cmake --install . --strip + + - name: '🚧 AVD Cache' + if: contains(matrix.config.name, 'android') + uses: actions/cache@v2 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-28 + + - name: '🚧 Create x86_64 tests environment' + if: contains(matrix.config.name, 'android') && steps.avd-cache.outputs.cache-hit != 'true' + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 28 + arch: ${{ matrix.config.arch }} + force-avd-creation: false + disable-animations: false + target: default + profile: Nexus 6 + emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -verbose -show-kernel + script: echo "Generated AVD snapshot for caching." + + - name: '🚧 Android x86_64 tests' + if: contains(matrix.config.name, 'android') + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 28 + force-avd-creation: false + disable-animations: true + arch: ${{ matrix.config.arch }} + target: default + profile: Nexus 6 + emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -verbose -show-kernel + script: bash ./adb.sh + - name: '📦 Pack artifact' shell: bash working-directory: instdir @@ -331,4 +431,4 @@ jobs: uses: actions/upload-artifact@v1 with: path: ./${{ matrix.config.artifact }} - name: ${{ matrix.config.artifact }} \ No newline at end of file + name: ${{ matrix.config.artifact }} diff --git a/.gitignore b/.gitignore index 9ecf5c78..9c529c95 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,7 @@ _*.txt _*.diff tmp/ +bindings/java/unicorn_Unicorn.h bindings/python/build/ bindings/python/dist/ bindings/python/src/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..5284170e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "docs/Unicorn_Engine_Documentation"] + path = docs/Unicorn_Engine_Documentation + url = git@github.com:kabeor/Unicorn-Engine-Documentation diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cc90e52..d6fb9bf2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,7 @@ else() endif() elseif(ANDROID_ABI) string(FIND "${ANDROID_ABI}" "arm64" UC_RET) + file(WRITE ${CMAKE_BINARY_DIR}/adb.sh "#!/bin/bash\n\n# Auto-generated by CMakeLists.txt\n\nadb shell mkdir -p /data/local/tmp/build\n") if (${UC_RET} GREATER_EQUAL "0") set(UNICORN_TARGET_ARCH "aarch64") @@ -1031,6 +1032,9 @@ if (UNICORN_BUILD_SHARED) add_library(unicorn SHARED ${UNICORN_SRCS} ) + if (ANDROID_ABI) + file(APPEND ${CMAKE_BINARY_DIR}/adb.sh "adb push ./libunicorn.so /data/local/tmp/build/\n") + endif() else() add_library(unicorn STATIC ${UNICORN_SRCS} @@ -1167,22 +1171,27 @@ if(UNICORN_FUZZ) endforeach() else() foreach(SAMPLE_FILE ${UNICORN_SAMPLE_FILE}) - add_executable(${SAMPLE_FILE} - ${CMAKE_CURRENT_SOURCE_DIR}/samples/${SAMPLE_FILE}.c - ) - target_link_libraries(${SAMPLE_FILE} - ${SAMPLES_LIB} - ) - endforeach(SAMPLE_FILE) + add_executable(${SAMPLE_FILE} + ${CMAKE_CURRENT_SOURCE_DIR}/samples/${SAMPLE_FILE}.c + ) + target_link_libraries(${SAMPLE_FILE} + ${SAMPLES_LIB} + ) + endforeach(SAMPLE_FILE) - foreach(TEST_FILE ${UNICORN_TEST_FILE}) - add_executable(${TEST_FILE} - ${CMAKE_CURRENT_SOURCE_DIR}/tests/unit/${TEST_FILE}.c - ) - target_link_libraries(${TEST_FILE} - ${SAMPLES_LIB} - ) - add_test(${TEST_FILE} ${TEST_FILE}) + foreach(TEST_FILE ${UNICORN_TEST_FILE}) + add_executable(${TEST_FILE} + ${CMAKE_CURRENT_SOURCE_DIR}/tests/unit/${TEST_FILE}.c + ) + target_link_libraries(${TEST_FILE} + ${SAMPLES_LIB} + ) + add_test(${TEST_FILE} ${TEST_FILE}) + if (ANDROID_ABI) + file(APPEND ${CMAKE_BINARY_DIR}/adb.sh "adb push ${TEST_FILE} /data/local/tmp/build/\n") + file(APPEND ${CMAKE_BINARY_DIR}/adb.sh "adb shell \"chmod +x /data/local/tmp/build/${TEST_FILE}\"\n") + file(APPEND ${CMAKE_BINARY_DIR}/adb.sh "adb shell \'LD_LIBRARY_PATH=/data/local/tmp/build:$LD_LIBRARY_PATH /data/local/tmp/build/${TEST_FILE}\' || exit -1\n") + endif() endforeach(TEST_FILE) endif() diff --git a/CREDITS.TXT b/CREDITS.TXT index 47cd8105..11df0628 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -79,3 +79,4 @@ Simon Gorchakov: PowerPC target Stuart Dootson (studoot): MSVC compatibility with PowerPC target support Ziqiao Kong (lazymio): uc_context_free() API and various bug fix & improvement. Sven Almgren (blindmatrix): bug fix +Chenxu Wu (kabeor): Documentation diff --git a/bindings/java/Makefile.build b/bindings/java/Makefile.build index c63fef3a..62b2b76e 100644 --- a/bindings/java/Makefile.build +++ b/bindings/java/Makefile.build @@ -1,9 +1,11 @@ .PHONY: gen_const clean -JAVA_HOME := $(shell jrunscript -e 'java.lang.System.out.println(java.lang.System.getProperty("java.home"));') +JC=javac -JAVA_INC := $(shell realpath $(JAVA_HOME)/../include) +JAVA_HOME := $(shell readlink -f `which $(JC)` | sed "s:/bin/$(JC)::") + +JAVA_INC := $(shell realpath $(JAVA_HOME)/include) JAVA_PLATFORM_INC := $(shell dirname `find $(JAVA_INC) -name jni_md.h`) @@ -28,7 +30,6 @@ LIBS=-lunicorn LIBDIR=-L../../ INCS=-I$(JAVA_INC) -I$(JAVA_PLATFORM_INC) -I$(UNICORN_INC) -JC=javac CLASSPATH=./ .SUFFIXES: .java .class @@ -46,7 +47,7 @@ all: lib jar samples $(CC) -c $(CFLAGS) $(INCS) $< -o $@ unicorn_Unicorn.h: unicorn/Unicorn.java - javah unicorn.Unicorn + javac -h . $< unicorn_Unicorn.o: unicorn_Unicorn.c unicorn_Unicorn.h $(CC) -c $(CFLAGS) $(INCS) $< -o $@ @@ -63,12 +64,12 @@ jar: jarfiles jar cf $(JARFILE) unicorn/*.class install: lib jar - cp libunicorn_java$(LIB_EXT) $(JAVA_HOME)/lib/ext - cp $(JARFILE) $(JAVA_HOME)/lib/ext + cp libunicorn_java$(LIB_EXT) /usr/lib + cp $(JARFILE) /usr/share/java uninstall: - rm $(JAVA_HOME)/lib/ext/libunicorn_java$(LIB_EXT) - rm $(JAVA_HOME)/lib/ext/$(JARFILE) + rm /usr/lib/libunicorn_java$(LIB_EXT) + rm /usr/share/java/$(JARFILE) gen_const: cd .. && python const_generator.py java diff --git a/bindings/java/samples/SampleNetworkAuditing.java b/bindings/java/samples/SampleNetworkAuditing.java index 929ceb9c..7a822acb 100644 --- a/bindings/java/samples/SampleNetworkAuditing.java +++ b/bindings/java/samples/SampleNetworkAuditing.java @@ -30,12 +30,12 @@ import java.util.*; public class SampleNetworkAuditing { - public static int next_id = 3; + public static long next_id = 3; public static final int SIZE_REG = 4; private static LogChain fd_chains = new LogChain(); - public static int get_id() { + public static long get_id() { return next_id++; } @@ -112,7 +112,7 @@ public class SampleNetworkAuditing { long mode = edx; String filename = read_string(uc, filename_addr); - Long dummy_fd = new Long(get_id()); + Long dummy_fd = get_id(); uc.reg_write(Unicorn.UC_X86_REG_EAX, dummy_fd); String msg = String.format("open file (filename=%s flags=%d mode=%d) with fd(%d)", filename, flags, mode, dummy_fd); @@ -144,8 +144,8 @@ public class SampleNetworkAuditing { long sock_type = toInt(uc.mem_read(args + SIZE_REG, SIZE_REG)); long protocol = toInt(uc.mem_read(args + SIZE_REG * 2, SIZE_REG)); - Long dummy_fd = new Long(get_id()); - uc.reg_write(Unicorn.UC_X86_REG_EAX, dummy_fd.intValue()); + Long dummy_fd = get_id(); + uc.reg_write(Unicorn.UC_X86_REG_EAX, dummy_fd); if (family == 2) { // AF_INET String msg = String.format("create socket (%s, %s) with fd(%d)", ADDR_FAMILY.get(family), SOCKET_TYPES.get(sock_type), dummy_fd); @@ -401,7 +401,7 @@ public class SampleNetworkAuditing { mu.mem_write(ADDRESS, code); // initialize stack - mu.reg_write(Unicorn.UC_X86_REG_ESP, new Long(ADDRESS + 0x200000)); + mu.reg_write(Unicorn.UC_X86_REG_ESP, ADDRESS + 0x200000L); // handle interrupt ourself mu.hook_add(new MyInterruptHook(), null); diff --git a/bindings/java/samples/Sample_arm.java b/bindings/java/samples/Sample_arm.java index a4bd1952..4d85fb7d 100644 --- a/bindings/java/samples/Sample_arm.java +++ b/bindings/java/samples/Sample_arm.java @@ -40,9 +40,9 @@ public class Sample_arm { static void test_arm() { - Long r0 = new Long(0x1234); // R0 register - Long r2 = new Long(0x6789); // R1 register - Long r3 = new Long(0x3333); // R2 register + Long r0 = 0x1234L; // R0 register + Long r2 = 0x6789L; // R1 register + Long r3 = 0x3333L; // R2 register Long r1; // R1 register System.out.print("Emulate ARM code\n"); @@ -85,7 +85,7 @@ public class Sample_arm { static void test_thumb() { - Long sp = new Long(0x1234); // R0 register + Long sp = 0x1234L; // R0 register System.out.print("Emulate THUMB code\n"); diff --git a/bindings/java/samples/Sample_arm64.java b/bindings/java/samples/Sample_arm64.java index 56a7212f..0f7e5f32 100644 --- a/bindings/java/samples/Sample_arm64.java +++ b/bindings/java/samples/Sample_arm64.java @@ -69,9 +69,9 @@ public class Sample_arm64 { static void test_arm64() { - Long x11 = new Long(0x1234); // X11 register - Long x13 = new Long(0x6789); // X13 register - Long x15 = new Long(0x3333); // X15 register + Long x11 = 0x1234L; // X11 register + Long x13 = 0x6789L; // X13 register + Long x15 = 0x3333L; // X15 register System.out.print("Emulate ARM64 code\n"); diff --git a/bindings/java/samples/Sample_m68k.java b/bindings/java/samples/Sample_m68k.java index cae025a6..f4658aff 100644 --- a/bindings/java/samples/Sample_m68k.java +++ b/bindings/java/samples/Sample_m68k.java @@ -68,26 +68,26 @@ public class Sample_m68k { static void test_m68k() { - Long d0 = new Long(0x0000); // d0 data register - Long d1 = new Long(0x0000); // d1 data register - Long d2 = new Long(0x0000); // d2 data register - Long d3 = new Long(0x0000); // d3 data register - Long d4 = new Long(0x0000); // d4 data register - Long d5 = new Long(0x0000); // d5 data register - Long d6 = new Long(0x0000); // d6 data register - Long d7 = new Long(0x0000); // d7 data register - - Long a0 = new Long(0x0000); // a0 address register - Long a1 = new Long(0x0000); // a1 address register - Long a2 = new Long(0x0000); // a2 address register - Long a3 = new Long(0x0000); // a3 address register - Long a4 = new Long(0x0000); // a4 address register - Long a5 = new Long(0x0000); // a5 address register - Long a6 = new Long(0x0000); // a6 address register - Long a7 = new Long(0x0000); // a6 address register - - Long pc = new Long(0x0000); // program counter - Long sr = new Long(0x0000); // status register + Long d0 = 0x0000L; // d0 data register + Long d1 = 0x0000L; // d1 data register + Long d2 = 0x0000L; // d2 data register + Long d3 = 0x0000L; // d3 data register + Long d4 = 0x0000L; // d4 data register + Long d5 = 0x0000L; // d5 data register + Long d6 = 0x0000L; // d6 data register + Long d7 = 0x0000L; // d7 data register + + Long a0 = 0x0000L; // a0 address register + Long a1 = 0x0000L; // a1 address register + Long a2 = 0x0000L; // a2 address register + Long a3 = 0x0000L; // a3 address register + Long a4 = 0x0000L; // a4 address register + Long a5 = 0x0000L; // a5 address register + Long a6 = 0x0000L; // a6 address register + Long a7 = 0x0000L; // a6 address register + + Long pc = 0x0000L; // program counter + Long sr = 0x0000L; // status register System.out.print("Emulate M68K code\n"); diff --git a/bindings/java/samples/Sample_mips.java b/bindings/java/samples/Sample_mips.java index d977c231..e338864f 100644 --- a/bindings/java/samples/Sample_mips.java +++ b/bindings/java/samples/Sample_mips.java @@ -70,7 +70,7 @@ public class Sample_mips { static void test_mips_eb() { - Long r1 = new Long(0x6789); // R1 register + Long r1 = 0x6789L; // R1 register System.out.print("Emulate MIPS code (big-endian)\n"); @@ -107,7 +107,7 @@ public class Sample_mips { static void test_mips_el() { - Long r1 = new Long(0x6789); // R1 register + Long r1 = 0x6789L; // R1 register System.out.print("===========================\n"); System.out.print("Emulate MIPS code (little-endian)\n"); diff --git a/bindings/java/samples/Sample_sparc.java b/bindings/java/samples/Sample_sparc.java index 85d26367..b2849f45 100644 --- a/bindings/java/samples/Sample_sparc.java +++ b/bindings/java/samples/Sample_sparc.java @@ -69,9 +69,9 @@ public class Sample_sparc { static void test_sparc() { - Long g1 = new Long(0x1230); // G1 register - Long g2 = new Long(0x6789); // G2 register - Long g3 = new Long(0x5555); // G3 register + Long g1 = 0x1230L; // G1 register + Long g2 = 0x6789L; // G2 register + Long g3 = 0x5555L; // G3 register System.out.print("Emulate SPARC code\n"); diff --git a/bindings/java/samples/Sample_x86.java b/bindings/java/samples/Sample_x86.java index e25df640..652663f8 100644 --- a/bindings/java/samples/Sample_x86.java +++ b/bindings/java/samples/Sample_x86.java @@ -171,8 +171,8 @@ public class Sample_x86 { } static void test_i386() { - Long r_ecx = new Long(0x1234); // ECX register - Long r_edx = new Long(0x7890); // EDX register + Long r_ecx = 0x1234L; // ECX register + Long r_edx = 0x7890L; // EDX register System.out.print("Emulate i386 code\n"); @@ -234,8 +234,8 @@ public class Sample_x86 { static void test_i386_inout() { - Long r_eax = new Long(0x1234); // ECX register - Long r_ecx = new Long(0x6789); // EDX register + Long r_eax = 0x1234L; // ECX register + Long r_ecx = 0x6789L; // EDX register System.out.print("===================================\n"); System.out.print("Emulate i386 code with IN/OUT instructions\n"); @@ -309,8 +309,8 @@ public class Sample_x86 { // emulate code that loop forever static void test_i386_loop() { - Long r_ecx = new Long(0x1234); // ECX register - Long r_edx = new Long(0x7890); // EDX register + Long r_ecx = 0x1234L; // ECX register + Long r_edx = 0x7890L; // EDX register System.out.print("===================================\n"); System.out.print("Emulate i386 code that loop forever\n"); @@ -346,8 +346,8 @@ public class Sample_x86 { // emulate code that read invalid memory static void test_i386_invalid_mem_read() { - Long r_ecx = new Long(0x1234); // ECX register - Long r_edx = new Long(0x7890); // EDX register + Long r_ecx = 0x1234L; // ECX register + Long r_edx = 0x7890L; // EDX register System.out.print("===================================\n"); System.out.print("Emulate i386 code that read from invalid memory\n"); @@ -393,8 +393,8 @@ public class Sample_x86 { // emulate code that read invalid memory static void test_i386_invalid_mem_write() { - Long r_ecx = new Long(0x1234); // ECX register - Long r_edx = new Long(0x7890); // EDX register + Long r_ecx = 0x1234L; // ECX register + Long r_edx = 0x7890L; // EDX register System.out.print("===================================\n"); System.out.print("Emulate i386 code that write to invalid memory\n"); @@ -453,8 +453,8 @@ public class Sample_x86 { // emulate code that jump to invalid memory static void test_i386_jump_invalid() { - Long r_ecx = new Long(0x1234); // ECX register - Long r_edx = new Long(0x7890); // EDX register + Long r_ecx = 0x1234L; // ECX register + Long r_edx = 0x7890L; // EDX register System.out.print("===================================\n"); System.out.print("Emulate i386 code that jumps to invalid memory\n"); @@ -527,22 +527,22 @@ public class Sample_x86 { u.mem_write(ADDRESS, X86_CODE64); // initialize machine registers - u.reg_write(Unicorn.UC_X86_REG_RSP, new Long(rsp)); - - u.reg_write(Unicorn.UC_X86_REG_RAX, new Long(rax)); - u.reg_write(Unicorn.UC_X86_REG_RBX, new Long(rbx)); - u.reg_write(Unicorn.UC_X86_REG_RCX, new Long(rcx)); - u.reg_write(Unicorn.UC_X86_REG_RDX, new Long(rdx)); - u.reg_write(Unicorn.UC_X86_REG_RSI, new Long(rsi)); - u.reg_write(Unicorn.UC_X86_REG_RDI, new Long(rdi)); - u.reg_write(Unicorn.UC_X86_REG_R8, new Long(r8)); - u.reg_write(Unicorn.UC_X86_REG_R9, new Long(r9)); - u.reg_write(Unicorn.UC_X86_REG_R10, new Long(r10)); - u.reg_write(Unicorn.UC_X86_REG_R11, new Long(r11)); - u.reg_write(Unicorn.UC_X86_REG_R12, new Long(r12)); - u.reg_write(Unicorn.UC_X86_REG_R13, new Long(r13)); - u.reg_write(Unicorn.UC_X86_REG_R14, new Long(r14)); - u.reg_write(Unicorn.UC_X86_REG_R15, new Long(r15)); + u.reg_write(Unicorn.UC_X86_REG_RSP, rsp); + + u.reg_write(Unicorn.UC_X86_REG_RAX, rax); + u.reg_write(Unicorn.UC_X86_REG_RBX, rbx); + u.reg_write(Unicorn.UC_X86_REG_RCX, rcx); + u.reg_write(Unicorn.UC_X86_REG_RDX, rdx); + u.reg_write(Unicorn.UC_X86_REG_RSI, rsi); + u.reg_write(Unicorn.UC_X86_REG_RDI, rdi); + u.reg_write(Unicorn.UC_X86_REG_R8, r8); + u.reg_write(Unicorn.UC_X86_REG_R9, r9); + u.reg_write(Unicorn.UC_X86_REG_R10, r10); + u.reg_write(Unicorn.UC_X86_REG_R11, r11); + u.reg_write(Unicorn.UC_X86_REG_R12, r12); + u.reg_write(Unicorn.UC_X86_REG_R13, r13); + u.reg_write(Unicorn.UC_X86_REG_R14, r14); + u.reg_write(Unicorn.UC_X86_REG_R15, r15); // tracing all basic blocks with customized callback u.hook_add(new MyBlockHook(), 1, 0, null); @@ -598,9 +598,9 @@ public class Sample_x86 { static void test_x86_16() { - Long eax = new Long(7); - Long ebx = new Long(5); - Long esi = new Long(6); + Long eax = 7L; + Long ebx = 5L; + Long esi = 6L; System.out.print("Emulate x86 16-bit code\n"); diff --git a/bindings/java/samples/Sample_x86_mmr.java b/bindings/java/samples/Sample_x86_mmr.java index e2b1a6dd..0ecb3a1e 100644 --- a/bindings/java/samples/Sample_x86_mmr.java +++ b/bindings/java/samples/Sample_x86_mmr.java @@ -49,7 +49,7 @@ public class Sample_x86_mmr { uc.reg_write(Unicorn.UC_X86_REG_LDTR, ldtr1); uc.reg_write(Unicorn.UC_X86_REG_GDTR, gdtr1); - uc.reg_write(Unicorn.UC_X86_REG_EAX, new Long(0xdddddddd)); + uc.reg_write(Unicorn.UC_X86_REG_EAX, 0xddddddddL); // read the registers back out eax = (int)((Long)uc.reg_read(Unicorn.UC_X86_REG_EAX)).longValue(); diff --git a/bindings/java/samples/Shellcode.java b/bindings/java/samples/Shellcode.java index 48674a46..e75d922b 100644 --- a/bindings/java/samples/Shellcode.java +++ b/bindings/java/samples/Shellcode.java @@ -113,7 +113,7 @@ public class Shellcode { static void test_i386() { - Long r_esp = new Long(ADDRESS + 0x200000); // ESP register + Long r_esp = ADDRESS + 0x200000L; // ESP register System.out.print("Emulate i386 code\n"); @@ -158,4 +158,4 @@ public class Shellcode { } -} \ No newline at end of file +} diff --git a/bindings/java/unicorn/Unicorn.java b/bindings/java/unicorn/Unicorn.java index 279fdbbf..26f04dec 100644 --- a/bindings/java/unicorn/Unicorn.java +++ b/bindings/java/unicorn/Unicorn.java @@ -25,7 +25,7 @@ import java.util.*; public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, SparcConst, MipsConst, X86Const { - private long eng; + public long eng; private int arch; private int mode; diff --git a/bindings/rust/Cargo.toml b/bindings/rust/Cargo.toml index d609fd03..45d10f16 100644 --- a/bindings/rust/Cargo.toml +++ b/bindings/rust/Cargo.toml @@ -1,8 +1,8 @@ [package] -name = "unicorn" -version = "1.0.0" -authors = ["Lukas Seidel"] -documentation = "" +name = "unicorn-engine" +version = "2.0.0-rc3" +authors = ["Ziqiao Kong", "Lukas Seidel"] +documentation = "https://github.com/unicorn-engine/unicorn/wiki" edition = "2018" include = [ "/.gitmodules", @@ -10,6 +10,7 @@ include = [ "/Cargo.toml", "/README.md", "/src/*", + "build.rs" ] license = "GPL-2.0" readme = "README.md" diff --git a/bindings/rust/README.md b/bindings/rust/README.md index 014e1a60..dba1d53c 100644 --- a/bindings/rust/README.md +++ b/bindings/rust/README.md @@ -1,17 +1,17 @@ -# unicorn-rs +# Unicorn-engine Rust bindings for the [Unicorn](http://www.unicorn-engine.org/) emulator with utility functions. -An extended version for fuzzing with AFL++ support can be found in https://github.com/aflplusplus/unicornafl. +Checkout Unicorn2 source code at [dev branch](https://github.com/unicorn-engine/unicorn/tree/dev). ```rust -use unicorn::RegisterARM; -use unicorn::unicorn_const::{Arch, Mode, Permission, SECOND_SCALE}; +use unicorn_engine::RegisterARM; +use unicorn_engine::unicorn_const::{Arch, Mode, Permission, SECOND_SCALE}; fn main() { let arm_code32: Vec = vec![0x17, 0x00, 0x40, 0xe2]; // sub r0, #23 - let mut unicorn = unicorn::Unicorn::new(Arch::ARM, Mode::LITTLE_ENDIAN).expect("failed to initialize Unicorn instance"); + let mut unicorn = unicorn-engine::Unicorn::new(Arch::ARM, Mode::LITTLE_ENDIAN).expect("failed to initialize Unicorn instance"); let mut emu = unicorn.borrow(); emu.mem_map(0x1000, 0x4000, Permission::ALL).expect("failed to map code page"); emu.mem_write(0x1000, &arm_code32).expect("failed to write instructions"); @@ -26,20 +26,18 @@ fn main() { ``` Further sample code can be found in ```tests/unicorn.rs```. -## Installation +## Usage -This project has been tested on Linux, OS X and Windows. - -To use unicorn-rs, simply add it as a dependency to the Cargo.toml of your program. +Add this to your `Cargo.toml`: ``` [dependencies] -unicorn = { path = "/path/to/bindings/rust", version="1.0.0" } +unicorn-engine = "2.0.0-rc3" ``` ## Acknowledgements These bindings are based on Sébastien Duquette's (@ekse) [unicorn-rs](https://github.com/unicorn-rs/unicorn-rs). We picked up the project, as it is no longer maintained. -Thanks to all contributers. +Thanks to all contributors. diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs index 7df3e61c..c128ef14 100644 --- a/bindings/rust/build.rs +++ b/bindings/rust/build.rs @@ -1,20 +1,128 @@ +use std::result::Result; use std::{env, process::Command}; -use build_helper::rustc::{link_lib, link_search}; - fn main() { - println!("cargo:rerun-if-changed=unicorn"); let out_dir = env::var("OUT_DIR").unwrap(); - let unicorn = "libunicorn.a"; - let _ = Command::new("cp") - .current_dir("../..") - .arg(&unicorn) - .arg(&out_dir) - .status() - .unwrap(); - link_search( - Some(build_helper::SearchKind::Native), - build_helper::out_dir(), - ); - link_lib(Some(build_helper::LibKind::Static), "unicorn"); + let profile = env::var("PROFILE").unwrap(); + let mut version = String::from("dev"); + if let Result::Ok(version_env) = env::var("UNICORN_BRANCH") { + version = version_env; + } + + let unicorn_dir; + if let Result::Ok(_) = env::var("CI") { + unicorn_dir = format!("../.."); + } else { + unicorn_dir = format!("{}/unicorn_git", out_dir); + + Command::new("rm").arg("-rf").arg(&unicorn_dir); + + Command::new("git") + .arg("clone") + .arg("git@github.com:unicorn-engine/unicorn.git") + .arg("-b") + .arg(version) + .arg(&unicorn_dir) + .output() + .expect("Fail to clone Unicorn repository."); + } + + println!("cargo:rerun-if-changed={}", &unicorn_dir); + + // We don't use TARGET since we can't cross-build. + if env::consts::OS == "windows" { + // Windows + let mut cmd = Command::new("cmake"); + cmd.current_dir(&unicorn_dir) + .arg("-B") + .arg("rust_build") + .arg("-DUNICORN_BUILD_SHARED=off") + .arg("-G") + .arg("Visual Studio 16 2019"); + + if profile == "debug" { + cmd.arg("-DCMAKE_BUILD_TYPE=Debug"); + } else { + cmd.arg("-DCMAKE_BUILD_TYPE=Release"); + } + + cmd.output() + .expect("Fail to create build directory on Windows."); + + let mut platform = "x64"; + let mut conf = "Release"; + if std::mem::size_of::() == 4 { + platform = "Win32"; + } + if profile == "debug" { + conf = "Debug"; + } + + Command::new("msbuild") + .current_dir(format!("{}/rust_build", &unicorn_dir)) + .arg("unicorn.sln") + .arg("-m") + .arg("-p:Platform=".to_owned() + platform) + .arg("-p:Configuration=".to_owned() + conf) + .output() + .expect("Fail to build unicorn on Win32."); + println!( + "cargo:rustc-link-search={}/rust_build/{}", + unicorn_dir, conf + ); + } else { + // Most Unix-like systems + let mut cmd = Command::new("cmake"); + cmd.current_dir(&unicorn_dir) + .arg("-B") + .arg("rust_build") + .arg("-DUNICORN_BUILD_SHARED=off"); + + if profile == "debug" { + cmd.arg("-DCMAKE_BUILD_TYPE=Debug"); + } else { + cmd.arg("-DCMAKE_BUILD_TYPE=Release"); + } + + cmd.output() + .expect("Fail to create build directory on *nix."); + + Command::new("make") + .current_dir(format!("{}/rust_build", &unicorn_dir)) + .arg("-j6") + .output() + .expect("Fail to build unicorn on *nix."); + + println!("cargo:rustc-link-search={}/rust_build", unicorn_dir); + } + + // This is a workaround for Unicorn static link since libunicorn.a is also linked again lib*-softmmu.a. + // Static libs is just a bundle of objects files. The link relation defined in CMakeLists is only + // valid within the cmake project scope and cmake would help link again sub static libs automatically. + // + // Lazymio(@wtdcode): Why do I stick to static link? See: https://github.com/rust-lang/cargo/issues/5077 + println!("cargo:rustc-link-lib=unicorn"); + for arch in [ + "x86_64", + "arm", + "armeb", + "aarch64", + "aarch64eb", + "riscv32", + "riscv64", + "mips", + "mipsel", + "mips64", + "mips64el", + "sparc", + "sparc64", + "m68k", + "ppc", + "ppc64", + ] + .iter() + { + println!("cargo:rustc-link-lib={}-softmmu", arch); + } + println!("cargo:rustc-link-lib=unicorn-common"); } diff --git a/bindings/rust/src/arm.rs b/bindings/rust/src/arm.rs index 69178664..6d72cefe 100644 --- a/bindings/rust/src/arm.rs +++ b/bindings/rust/src/arm.rs @@ -123,8 +123,31 @@ pub enum RegisterARM { MSP = 115, PSP = 116, CONTROL = 117, - XPSR = 118, - ENDING = 119, + IAPSR = 118, + EAPSR = 119, + XPSR = 120, + EPSR = 121, + IEPSR = 122, + PRIMASK = 123, + BASEPRI = 124, + BASEPRI_MAX = 125, + FAULTMASK = 126, + APSR_NZCVQ = 127, + APSR_G = 128, + APSR_NZCVQG = 129, + IAPSR_NZCVQ = 130, + IAPSR_G = 131, + IAPSR_NZCVQG = 132, + EAPSR_NZCVQ = 133, + EAPSR_G = 134, + EAPSR_NZCVQG = 135, + XPSR_NZCVQ = 136, + XPSR_G = 137, + XPSR_NZCVQG = 138, + ENDING = 139, +} + +impl RegisterARM { // alias registers // (assoc) R13 = 12, // (assoc) R14 = 10, @@ -133,9 +156,6 @@ pub enum RegisterARM { // (assoc) SL = 76, // (assoc) FP = 77, // (assoc) IP = 78, -} - -impl RegisterARM { pub const R13: RegisterARM = RegisterARM::SP; pub const R14: RegisterARM = RegisterARM::LR; pub const R15: RegisterARM = RegisterARM::PC; diff --git a/bindings/rust/src/arm64.rs b/bindings/rust/src/arm64.rs index 523de02a..299b1bbf 100644 --- a/bindings/rust/src/arm64.rs +++ b/bindings/rust/src/arm64.rs @@ -1,4 +1,5 @@ #![allow(non_camel_case_types)] +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT // ARM64 registers #[repr(C)] diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 8fb5ed3c..99e1531c 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -6,13 +6,13 @@ //! //! ```rust //! -//! use unicorn::RegisterARM; -//! use unicorn::unicorn_const::{Arch, Mode, Permission, SECOND_SCALE}; +//! use unicorn_engine::RegisterARM; +//! use unicorn_engine::unicorn_const::{Arch, Mode, Permission, SECOND_SCALE}; //! //! fn main() { //! let arm_code32: Vec = vec![0x17, 0x00, 0x40, 0xe2]; // sub r0, #23 //! -//! let mut unicorn = unicorn::Unicorn::new(Arch::ARM, Mode::LITTLE_ENDIAN).expect("failed to initialize Unicorn instance"); +//! let mut unicorn = unicorn_engine::Unicorn::new(Arch::ARM, Mode::LITTLE_ENDIAN).expect("failed to initialize Unicorn instance"); //! let mut emu = unicorn.borrow(); //! emu.mem_map(0x1000, 0x4000, Permission::ALL).expect("failed to map code page"); //! emu.mem_write(0x1000, &arm_code32).expect("failed to write instructions"); @@ -35,9 +35,10 @@ mod arm64; mod m68k; mod mips; mod ppc; +mod riscv; mod sparc; mod x86; -pub use crate::{arm::*, arm64::*, m68k::*, mips::*, ppc::*, sparc::*, x86::*}; +pub use crate::{arm::*, arm64::*, m68k::*, mips::*, ppc::*, riscv::*, sparc::*, x86::*}; use ffi::uc_handle; use std::collections::HashMap; diff --git a/bindings/rust/src/m68k.rs b/bindings/rust/src/m68k.rs index 6c04e851..54c62920 100644 --- a/bindings/rust/src/m68k.rs +++ b/bindings/rust/src/m68k.rs @@ -21,4 +21,5 @@ pub enum RegisterM68K { D7, SR, PC, + ENDING, } diff --git a/bindings/rust/src/mips.rs b/bindings/rust/src/mips.rs index 84cec434..5f462af0 100644 --- a/bindings/rust/src/mips.rs +++ b/bindings/rust/src/mips.rs @@ -1,4 +1,5 @@ #![allow(non_camel_case_types)] +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT // MIPS registers #[repr(C)] @@ -155,7 +156,11 @@ pub enum RegisterMIPS { MPL2 = 136, CP0_CONFIG3 = 137, CP0_USERLOCAL = 138, - ENDING = 139, + CP0_STATUS = 139, + ENDING = 140, +} + +impl RegisterMIPS { // alias registers // (assoc) ZERO = 2, // (assoc) AT = 3, @@ -198,9 +203,6 @@ pub enum RegisterMIPS { // (assoc) LO1 = 46, // (assoc) LO2 = 47, // (assoc) LO3 = 48, -} - -impl RegisterMIPS { pub const ZERO: RegisterMIPS = RegisterMIPS::GPR0; pub const AT: RegisterMIPS = RegisterMIPS::GPR1; pub const V0: RegisterMIPS = RegisterMIPS::GPR2; diff --git a/bindings/rust/src/riscv.rs b/bindings/rust/src/riscv.rs new file mode 100644 index 00000000..ca91c350 --- /dev/null +++ b/bindings/rust/src/riscv.rs @@ -0,0 +1,213 @@ +#![allow(non_camel_case_types)] +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +// RISCV registers +#[repr(C)] +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum RegisterRISCV { + INVALID = 0, + + // General purpose registers + X0 = 1, + X1 = 2, + X2 = 3, + X3 = 4, + X4 = 5, + X5 = 6, + X6 = 7, + X7 = 8, + X8 = 9, + X9 = 10, + X10 = 11, + X11 = 12, + X12 = 13, + X13 = 14, + X14 = 15, + X15 = 16, + X16 = 17, + X17 = 18, + X18 = 19, + X19 = 20, + X20 = 21, + X21 = 22, + X22 = 23, + X23 = 24, + X24 = 25, + X25 = 26, + X26 = 27, + X27 = 28, + X28 = 29, + X29 = 30, + X30 = 31, + X31 = 32, + + // Floating-point registers + F0 = 33, + F1 = 34, + F2 = 35, + F3 = 36, + F4 = 37, + F5 = 38, + F6 = 39, + F7 = 40, + F8 = 41, + F9 = 42, + F10 = 43, + F11 = 44, + F12 = 45, + F13 = 46, + F14 = 47, + F15 = 48, + F16 = 49, + F17 = 50, + F18 = 51, + F19 = 52, + F20 = 53, + F21 = 54, + F22 = 55, + F23 = 56, + F24 = 57, + F25 = 58, + F26 = 59, + F27 = 60, + F28 = 61, + F29 = 62, + F30 = 63, + F31 = 64, + PC = 65, + ENDING = 66, +} + +impl RegisterRISCV { + // Alias registers + // (assoc) ZERO = 1, + // (assoc) RA = 2, + // (assoc) SP = 3, + // (assoc) GP = 4, + // (assoc) TP = 5, + // (assoc) T0 = 6, + // (assoc) T1 = 7, + // (assoc) T2 = 8, + // (assoc) S0 = 9, + // (assoc) FP = 9, + // (assoc) S1 = 10, + // (assoc) A0 = 11, + // (assoc) A1 = 12, + // (assoc) A2 = 13, + // (assoc) A3 = 14, + // (assoc) A4 = 15, + // (assoc) A5 = 16, + // (assoc) A6 = 17, + // (assoc) A7 = 18, + // (assoc) S2 = 19, + // (assoc) S3 = 20, + // (assoc) S4 = 21, + // (assoc) S5 = 22, + // (assoc) S6 = 23, + // (assoc) S7 = 24, + // (assoc) S8 = 25, + // (assoc) S9 = 26, + // (assoc) S10 = 27, + // (assoc) S11 = 28, + // (assoc) T3 = 29, + // (assoc) T4 = 30, + // (assoc) T5 = 31, + // (assoc) T6 = 32, + // (assoc) FT0 = 33, + // (assoc) FT1 = 34, + // (assoc) FT2 = 35, + // (assoc) FT3 = 36, + // (assoc) FT4 = 37, + // (assoc) FT5 = 38, + // (assoc) FT6 = 39, + // (assoc) FT7 = 40, + // (assoc) FS0 = 41, + // (assoc) FS1 = 42, + // (assoc) FA0 = 43, + // (assoc) FA1 = 44, + // (assoc) FA2 = 45, + // (assoc) FA3 = 46, + // (assoc) FA4 = 47, + // (assoc) FA5 = 48, + // (assoc) FA6 = 49, + // (assoc) FA7 = 50, + // (assoc) FS2 = 51, + // (assoc) FS3 = 52, + // (assoc) FS4 = 53, + // (assoc) FS5 = 54, + // (assoc) FS6 = 55, + // (assoc) FS7 = 56, + // (assoc) FS8 = 57, + // (assoc) FS9 = 58, + // (assoc) FS10 = 59, + // (assoc) FS11 = 60, + // (assoc) FT8 = 61, + // (assoc) FT9 = 62, + // (assoc) FT10 = 63, + // (assoc) FT11 = 64, + pub const ZERO: RegisterRISCV = RegisterRISCV::X0; + pub const RA: RegisterRISCV = RegisterRISCV::X1; + pub const SP: RegisterRISCV = RegisterRISCV::X2; + pub const GP: RegisterRISCV = RegisterRISCV::X3; + pub const TP: RegisterRISCV = RegisterRISCV::X4; + pub const T0: RegisterRISCV = RegisterRISCV::X5; + pub const T1: RegisterRISCV = RegisterRISCV::X6; + pub const T2: RegisterRISCV = RegisterRISCV::X7; + pub const S0: RegisterRISCV = RegisterRISCV::X8; + pub const FP: RegisterRISCV = RegisterRISCV::X8; + pub const S1: RegisterRISCV = RegisterRISCV::X9; + pub const A0: RegisterRISCV = RegisterRISCV::X10; + pub const A1: RegisterRISCV = RegisterRISCV::X11; + pub const A2: RegisterRISCV = RegisterRISCV::X12; + pub const A3: RegisterRISCV = RegisterRISCV::X13; + pub const A4: RegisterRISCV = RegisterRISCV::X14; + pub const A5: RegisterRISCV = RegisterRISCV::X15; + pub const A6: RegisterRISCV = RegisterRISCV::X16; + pub const A7: RegisterRISCV = RegisterRISCV::X17; + pub const S2: RegisterRISCV = RegisterRISCV::X18; + pub const S3: RegisterRISCV = RegisterRISCV::X19; + pub const S4: RegisterRISCV = RegisterRISCV::X20; + pub const S5: RegisterRISCV = RegisterRISCV::X21; + pub const S6: RegisterRISCV = RegisterRISCV::X22; + pub const S7: RegisterRISCV = RegisterRISCV::X23; + pub const S8: RegisterRISCV = RegisterRISCV::X24; + pub const S9: RegisterRISCV = RegisterRISCV::X25; + pub const S10: RegisterRISCV = RegisterRISCV::X26; + pub const S11: RegisterRISCV = RegisterRISCV::X27; + pub const T3: RegisterRISCV = RegisterRISCV::X28; + pub const T4: RegisterRISCV = RegisterRISCV::X29; + pub const T5: RegisterRISCV = RegisterRISCV::X30; + pub const T6: RegisterRISCV = RegisterRISCV::X31; + pub const FT0: RegisterRISCV = RegisterRISCV::F0; + pub const FT1: RegisterRISCV = RegisterRISCV::F1; + pub const FT2: RegisterRISCV = RegisterRISCV::F2; + pub const FT3: RegisterRISCV = RegisterRISCV::F3; + pub const FT4: RegisterRISCV = RegisterRISCV::F4; + pub const FT5: RegisterRISCV = RegisterRISCV::F5; + pub const FT6: RegisterRISCV = RegisterRISCV::F6; + pub const FT7: RegisterRISCV = RegisterRISCV::F7; + pub const FS0: RegisterRISCV = RegisterRISCV::F8; + pub const FS1: RegisterRISCV = RegisterRISCV::F9; + pub const FA0: RegisterRISCV = RegisterRISCV::F10; + pub const FA1: RegisterRISCV = RegisterRISCV::F11; + pub const FA2: RegisterRISCV = RegisterRISCV::F12; + pub const FA3: RegisterRISCV = RegisterRISCV::F13; + pub const FA4: RegisterRISCV = RegisterRISCV::F14; + pub const FA5: RegisterRISCV = RegisterRISCV::F15; + pub const FA6: RegisterRISCV = RegisterRISCV::F16; + pub const FA7: RegisterRISCV = RegisterRISCV::F17; + pub const FS2: RegisterRISCV = RegisterRISCV::F18; + pub const FS3: RegisterRISCV = RegisterRISCV::F19; + pub const FS4: RegisterRISCV = RegisterRISCV::F20; + pub const FS5: RegisterRISCV = RegisterRISCV::F21; + pub const FS6: RegisterRISCV = RegisterRISCV::F22; + pub const FS7: RegisterRISCV = RegisterRISCV::F23; + pub const FS8: RegisterRISCV = RegisterRISCV::F24; + pub const FS9: RegisterRISCV = RegisterRISCV::F25; + pub const FS10: RegisterRISCV = RegisterRISCV::F26; + pub const FS11: RegisterRISCV = RegisterRISCV::F27; + pub const FT8: RegisterRISCV = RegisterRISCV::F28; + pub const FT9: RegisterRISCV = RegisterRISCV::F29; + pub const FT10: RegisterRISCV = RegisterRISCV::F30; + pub const FT11: RegisterRISCV = RegisterRISCV::F31; +} diff --git a/bindings/rust/src/sparc.rs b/bindings/rust/src/sparc.rs index 21e09db4..6c6892e6 100644 --- a/bindings/rust/src/sparc.rs +++ b/bindings/rust/src/sparc.rs @@ -1,3 +1,5 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + // SPARC registers #[repr(C)] #[derive(PartialEq, Debug, Clone, Copy)] @@ -91,4 +93,13 @@ pub enum RegisterSPARC { Y = 86, XCC = 87, PC = 88, + ENDING = 89, +} + +impl RegisterSPARC { + // alias registers + // (assoc) O6 = 84, + // (assoc) I6 = 67, + pub const O6: RegisterSPARC = RegisterSPARC::SP; + pub const I6: RegisterSPARC = RegisterSPARC::FP; } diff --git a/bindings/rust/src/unicorn_const.rs b/bindings/rust/src/unicorn_const.rs index 56b3f275..9cb14da7 100644 --- a/bindings/rust/src/unicorn_const.rs +++ b/bindings/rust/src/unicorn_const.rs @@ -1,11 +1,11 @@ #![allow(non_camel_case_types)] use bitflags::bitflags; -pub const API_MAJOR: u64 = 1; +pub const API_MAJOR: u64 = 2; pub const API_MINOR: u64 = 0; -pub const VERSION_MAJOR: u64 = 1; +pub const VERSION_MAJOR: u64 = 2; pub const VERSION_MINOR: u64 = 0; -pub const VERSION_EXTRA: u64 = 2; +pub const VERSION_EXTRA: u64 = 0; pub const SECOND_SCALE: u64 = 1_000_000; pub const MILISECOND_SCALE: u64 = 1_000; @@ -93,6 +93,7 @@ pub enum Query { MODE = 1, PAGE_SIZE = 2, ARCH = 3, + TIMEOUT = 4, } bitflags! { @@ -124,7 +125,8 @@ pub enum Arch { PPC = 5, SPARC = 6, M68K = 7, - MAX = 8, + RISCV = 8, + MAX = 9, } bitflags! { @@ -154,5 +156,7 @@ bitflags! { const SPARC32 = Self::MIPS32.bits; const SPARC64 = Self::MIPS64.bits; const V9 = Self::THUMB.bits; + const RISCV32 = Self::MIPS32.bits; + const RISCV64 = Self::MIPS64.bits; } } diff --git a/bindings/rust/src/x86.rs b/bindings/rust/src/x86.rs index 03c92176..7ed65230 100644 --- a/bindings/rust/src/x86.rs +++ b/bindings/rust/src/x86.rs @@ -1,257 +1,245 @@ +#![allow(non_camel_case_types)] +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + // X86 registers #[repr(C)] #[derive(PartialEq, Debug, Clone, Copy)] pub enum RegisterX86 { INVALID = 0, - AH, - AL, - AX, - BH, - BL, - BP, - BPL, - BX, - CH, - CL, - CS, - CX, - DH, - DI, - DIL, - DL, - DS, - DX, - EAX, - EBP, - EBX, - ECX, - EDI, - EDX, - EFLAGS, - EIP, - EIZ, - ES, - ESI, - ESP, - FPSW, - FS, - GS, - IP, - RAX, - RBP, - RBX, - RCX, - RDI, - RDX, - RIP, - RIZ, - RSI, - RSP, - SI, - SIL, - SP, - SPL, - SS, - CR0, - CR1, - CR2, - CR3, - CR4, - CR5, - CR6, - CR7, - CR8, - CR9, - CR10, - CR11, - CR12, - CR13, - CR14, - CR15, - DR0, - DR1, - DR2, - DR3, - DR4, - DR5, - DR6, - DR7, - DR8, - DR9, - DR10, - DR11, - DR12, - DR13, - DR14, - DR15, - FP0, - FP1, - FP2, - FP3, - FP4, - FP5, - FP6, - FP7, - K0, - K1, - K2, - K3, - K4, - K5, - K6, - K7, - MM0, - MM1, - MM2, - MM3, - MM4, - MM5, - MM6, - MM7, - R8, - R9, - R10, - R11, - R12, - R13, - R14, - R15, - ST0, - ST1, - ST2, - ST3, - ST4, - ST5, - ST6, - ST7, - XMM0, - XMM1, - XMM2, - XMM3, - XMM4, - XMM5, - XMM6, - XMM7, - XMM8, - XMM9, - XMM10, - XMM11, - XMM12, - XMM13, - XMM14, - XMM15, - XMM16, - XMM17, - XMM18, - XMM19, - XMM20, - XMM21, - XMM22, - XMM23, - XMM24, - XMM25, - XMM26, - XMM27, - XMM28, - XMM29, - XMM30, - XMM31, - YMM0, - YMM1, - YMM2, - YMM3, - YMM4, - YMM5, - YMM6, - YMM7, - YMM8, - YMM9, - YMM10, - YMM11, - YMM12, - YMM13, - YMM14, - YMM15, - YMM16, - YMM17, - YMM18, - YMM19, - YMM20, - YMM21, - YMM22, - YMM23, - YMM24, - YMM25, - YMM26, - YMM27, - YMM28, - YMM29, - YMM30, - YMM31, - ZMM0, - ZMM1, - ZMM2, - ZMM3, - ZMM4, - ZMM5, - ZMM6, - ZMM7, - ZMM8, - ZMM9, - ZMM10, - ZMM11, - ZMM12, - ZMM13, - ZMM14, - ZMM15, - ZMM16, - ZMM17, - ZMM18, - ZMM19, - ZMM20, - ZMM21, - ZMM22, - ZMM23, - ZMM24, - ZMM25, - ZMM26, - ZMM27, - ZMM28, - ZMM29, - ZMM30, - ZMM31, - R8B, - R9B, - R10B, - R11B, - R12B, - R13B, - R14B, - R15B, - R8D, - R9D, - R10D, - R11D, - R12D, - R13D, - R14D, - R15D, - R8W, - R9W, - R10W, - R11W, - R12W, - R13W, - R14W, - R15W, - IDTR, - GDTR, - LDTR, - TR, - FPCW, - FPTAG, - MSR, - MXCSR, + AH = 1, + AL = 2, + AX = 3, + BH = 4, + BL = 5, + BP = 6, + BPL = 7, + BX = 8, + CH = 9, + CL = 10, + CS = 11, + CX = 12, + DH = 13, + DI = 14, + DIL = 15, + DL = 16, + DS = 17, + DX = 18, + EAX = 19, + EBP = 20, + EBX = 21, + ECX = 22, + EDI = 23, + EDX = 24, + EFLAGS = 25, + EIP = 26, + ES = 27, + ESI = 28, + ESP = 29, + FPSW = 30, + FS = 31, + GS = 32, + IP = 33, + RAX = 34, + RBP = 35, + RBX = 36, + RCX = 37, + RDI = 38, + RDX = 39, + RIP = 40, + RSI = 41, + RSP = 42, + SI = 43, + SIL = 44, + SP = 45, + SPL = 46, + SS = 47, + CR0 = 48, + CR1 = 49, + CR2 = 50, + CR3 = 51, + CR4 = 52, + CR8 = 53, + DR0 = 54, + DR1 = 55, + DR2 = 56, + DR3 = 57, + DR4 = 58, + DR5 = 59, + DR6 = 60, + DR7 = 61, + FP0 = 62, + FP1 = 63, + FP2 = 64, + FP3 = 65, + FP4 = 66, + FP5 = 67, + FP6 = 68, + FP7 = 69, + K0 = 70, + K1 = 71, + K2 = 72, + K3 = 73, + K4 = 74, + K5 = 75, + K6 = 76, + K7 = 77, + MM0 = 78, + MM1 = 79, + MM2 = 80, + MM3 = 81, + MM4 = 82, + MM5 = 83, + MM6 = 84, + MM7 = 85, + R8 = 86, + R9 = 87, + R10 = 88, + R11 = 89, + R12 = 90, + R13 = 91, + R14 = 92, + R15 = 93, + ST0 = 94, + ST1 = 95, + ST2 = 96, + ST3 = 97, + ST4 = 98, + ST5 = 99, + ST6 = 100, + ST7 = 101, + XMM0 = 102, + XMM1 = 103, + XMM2 = 104, + XMM3 = 105, + XMM4 = 106, + XMM5 = 107, + XMM6 = 108, + XMM7 = 109, + XMM8 = 110, + XMM9 = 111, + XMM10 = 112, + XMM11 = 113, + XMM12 = 114, + XMM13 = 115, + XMM14 = 116, + XMM15 = 117, + XMM16 = 118, + XMM17 = 119, + XMM18 = 120, + XMM19 = 121, + XMM20 = 122, + XMM21 = 123, + XMM22 = 124, + XMM23 = 125, + XMM24 = 126, + XMM25 = 127, + XMM26 = 128, + XMM27 = 129, + XMM28 = 130, + XMM29 = 131, + XMM30 = 132, + XMM31 = 133, + YMM0 = 134, + YMM1 = 135, + YMM2 = 136, + YMM3 = 137, + YMM4 = 138, + YMM5 = 139, + YMM6 = 140, + YMM7 = 141, + YMM8 = 142, + YMM9 = 143, + YMM10 = 144, + YMM11 = 145, + YMM12 = 146, + YMM13 = 147, + YMM14 = 148, + YMM15 = 149, + YMM16 = 150, + YMM17 = 151, + YMM18 = 152, + YMM19 = 153, + YMM20 = 154, + YMM21 = 155, + YMM22 = 156, + YMM23 = 157, + YMM24 = 158, + YMM25 = 159, + YMM26 = 160, + YMM27 = 161, + YMM28 = 162, + YMM29 = 163, + YMM30 = 164, + YMM31 = 165, + ZMM0 = 166, + ZMM1 = 167, + ZMM2 = 168, + ZMM3 = 169, + ZMM4 = 170, + ZMM5 = 171, + ZMM6 = 172, + ZMM7 = 173, + ZMM8 = 174, + ZMM9 = 175, + ZMM10 = 176, + ZMM11 = 177, + ZMM12 = 178, + ZMM13 = 179, + ZMM14 = 180, + ZMM15 = 181, + ZMM16 = 182, + ZMM17 = 183, + ZMM18 = 184, + ZMM19 = 185, + ZMM20 = 186, + ZMM21 = 187, + ZMM22 = 188, + ZMM23 = 189, + ZMM24 = 190, + ZMM25 = 191, + ZMM26 = 192, + ZMM27 = 193, + ZMM28 = 194, + ZMM29 = 195, + ZMM30 = 196, + ZMM31 = 197, + R8B = 198, + R9B = 199, + R10B = 200, + R11B = 201, + R12B = 202, + R13B = 203, + R14B = 204, + R15B = 205, + R8D = 206, + R9D = 207, + R10D = 208, + R11D = 209, + R12D = 210, + R13D = 211, + R14D = 212, + R15D = 213, + R8W = 214, + R9W = 215, + R10W = 216, + R11W = 217, + R12W = 218, + R13W = 219, + R14W = 220, + R15W = 221, + IDTR = 222, + GDTR = 223, + LDTR = 224, + TR = 225, + FPCW = 226, + FPTAG = 227, + MSR = 228, + MXCSR = 229, + FS_BASE = 230, + GS_BASE = 231, + FLAGS = 232, + RFLAGS = 233, + ENDING = 234, } #[repr(C)] diff --git a/bindings/rust/tests/unicorn.rs b/bindings/rust/tests/unicorn.rs index 90021835..6f8f2143 100644 --- a/bindings/rust/tests/unicorn.rs +++ b/bindings/rust/tests/unicorn.rs @@ -1,11 +1,9 @@ -#![deny(rust_2018_idioms)] - use std::cell::RefCell; use std::rc::Rc; -use unicorn::unicorn_const::{uc_error, Arch, HookType, MemType, Mode, Permission, SECOND_SCALE}; -use unicorn::{InsnSysX86, RegisterARM, RegisterMIPS, RegisterPPC, RegisterX86}; +use unicorn_engine::unicorn_const::{uc_error, Arch, HookType, MemType, Mode, Permission, SECOND_SCALE}; +use unicorn_engine::{InsnSysX86, RegisterARM, RegisterMIPS, RegisterPPC, RegisterX86}; -pub static X86_REGISTERS: [RegisterX86; 145] = [ +pub static X86_REGISTERS: [RegisterX86; 125] = [ RegisterX86::AH, RegisterX86::AL, RegisterX86::AX, @@ -32,7 +30,6 @@ pub static X86_REGISTERS: [RegisterX86; 145] = [ RegisterX86::EDX, RegisterX86::EFLAGS, RegisterX86::EIP, - RegisterX86::EIZ, RegisterX86::ES, RegisterX86::ESI, RegisterX86::ESP, @@ -47,7 +44,6 @@ pub static X86_REGISTERS: [RegisterX86; 145] = [ RegisterX86::RDI, RegisterX86::RDX, RegisterX86::RIP, - RegisterX86::RIZ, RegisterX86::RSI, RegisterX86::RSP, RegisterX86::SI, @@ -60,17 +56,7 @@ pub static X86_REGISTERS: [RegisterX86; 145] = [ RegisterX86::CR2, RegisterX86::CR3, RegisterX86::CR4, - RegisterX86::CR5, - RegisterX86::CR6, - RegisterX86::CR7, RegisterX86::CR8, - RegisterX86::CR9, - RegisterX86::CR10, - RegisterX86::CR11, - RegisterX86::CR12, - RegisterX86::CR13, - RegisterX86::CR14, - RegisterX86::CR15, RegisterX86::DR0, RegisterX86::DR1, RegisterX86::DR2, @@ -79,14 +65,6 @@ pub static X86_REGISTERS: [RegisterX86; 145] = [ RegisterX86::DR5, RegisterX86::DR6, RegisterX86::DR7, - RegisterX86::DR8, - RegisterX86::DR9, - RegisterX86::DR10, - RegisterX86::DR11, - RegisterX86::DR12, - RegisterX86::DR13, - RegisterX86::DR14, - RegisterX86::DR15, RegisterX86::FP0, RegisterX86::FP1, RegisterX86::FP2, @@ -153,13 +131,13 @@ pub static X86_REGISTERS: [RegisterX86; 145] = [ RegisterX86::R15W, ]; -type Unicorn<'a> = unicorn::UnicornHandle<'a>; +type Unicorn<'a> = unicorn_engine::UnicornHandle<'a>; #[test] fn emulate_x86() { let x86_code32: Vec = vec![0x41, 0x4a]; // INC ecx; DEC edx - let mut unicorn = unicorn::Unicorn::new(Arch::X86, Mode::MODE_32) + let mut unicorn = unicorn_engine::Unicorn::new(Arch::X86, Mode::MODE_32) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.reg_write(RegisterX86::EAX as i32, 123), Ok(())); @@ -210,7 +188,7 @@ fn x86_code_callback() { let x86_code32: Vec = vec![0x41, 0x4a]; // INC ecx; DEC edx - let mut unicorn = unicorn::Unicorn::new(Arch::X86, Mode::MODE_32) + let mut unicorn = unicorn_engine::Unicorn::new(Arch::X86, Mode::MODE_32) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); @@ -241,7 +219,7 @@ fn x86_intr_callback() { let x86_code32: Vec = vec![0xcd, 0x80]; // INT 0x80; - let mut unicorn = unicorn::Unicorn::new(Arch::X86, Mode::MODE_32) + let mut unicorn = unicorn_engine::Unicorn::new(Arch::X86, Mode::MODE_32) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); @@ -278,9 +256,15 @@ fn x86_mem_callback() { let callback_mems = mems_cell.clone(); let callback = - move |_: Unicorn<'_>, mem_type: MemType, address: u64, size: usize, value: i64| { + move |uc: Unicorn<'_>, mem_type: MemType, address: u64, size: usize, value: i64| { let mut mems = callback_mems.borrow_mut(); + let mut uc = uc; + mems.push(MemExpectation(mem_type, address, size, value)); + + if mem_type == MemType::READ_UNMAPPED { + uc.mem_map(address, 0x1000, Permission::ALL).unwrap(); + } }; // mov eax, 0xdeadbeef; @@ -290,7 +274,7 @@ fn x86_mem_callback() { 0xB8, 0xEF, 0xBE, 0xAD, 0xDE, 0xA3, 0x00, 0x20, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x01, 0x00, ]; - let mut unicorn = unicorn::Unicorn::new(Arch::X86, Mode::MODE_32) + let mut unicorn = unicorn_engine::Unicorn::new(Arch::X86, Mode::MODE_32) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); @@ -307,7 +291,7 @@ fn x86_mem_callback() { 10 * SECOND_SCALE, 0x1000 ), - Err(uc_error::READ_UNMAPPED) + Ok(()) ); assert_eq!(expects, *mems_cell.borrow()); @@ -328,7 +312,7 @@ fn x86_insn_in_callback() { let x86_code32: Vec = vec![0xe5, 0x10]; // IN eax, 0x10; - let mut unicorn = unicorn::Unicorn::new(Arch::X86, Mode::MODE_32) + let mut unicorn = unicorn_engine::Unicorn::new(Arch::X86, Mode::MODE_32) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); @@ -365,7 +349,7 @@ fn x86_insn_out_callback() { let x86_code32: Vec = vec![0xb0, 0x32, 0xe6, 0x46]; // MOV al, 0x32; OUT 0x46, al; - let mut unicorn = unicorn::Unicorn::new(Arch::X86, Mode::MODE_32) + let mut unicorn = unicorn_engine::Unicorn::new(Arch::X86, Mode::MODE_32) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); @@ -407,7 +391,7 @@ fn x86_insn_sys_callback() { 0x48, 0xB8, 0xEF, 0xBE, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x05, ]; - let mut unicorn = unicorn::Unicorn::new(Arch::X86, Mode::MODE_64) + let mut unicorn = unicorn_engine::Unicorn::new(Arch::X86, Mode::MODE_64) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); @@ -434,7 +418,7 @@ fn x86_insn_sys_callback() { fn emulate_arm() { let arm_code32: Vec = vec![0x83, 0xb0]; // sub sp, #0xc - let mut unicorn = unicorn::Unicorn::new(Arch::ARM, Mode::THUMB) + let mut unicorn = unicorn_engine::Unicorn::new(Arch::ARM, Mode::THUMB) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.reg_write(RegisterARM::R1 as i32, 123), Ok(())); @@ -475,7 +459,7 @@ fn emulate_arm() { fn emulate_mips() { let mips_code32 = vec![0x56, 0x34, 0x21, 0x34]; // ori $at, $at, 0x3456; - let mut unicorn = unicorn::Unicorn::new(Arch::MIPS, Mode::MODE_32) + let mut unicorn = unicorn_engine::Unicorn::new(Arch::MIPS, Mode::MODE_32) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); @@ -501,7 +485,7 @@ fn emulate_mips() { fn emulate_ppc() { let ppc_code32 = vec![0x7F, 0x46, 0x1A, 0x14]; // add 26, 6, 3 - let mut unicorn = unicorn::Unicorn::new(Arch::PPC, Mode::PPC32) + let mut unicorn = unicorn_engine::Unicorn::new(Arch::PPC, Mode::PPC32 | Mode::BIG_ENDIAN) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); @@ -526,7 +510,7 @@ fn emulate_ppc() { #[test] fn mem_unmapping() { - let mut unicorn = unicorn::Unicorn::new(Arch::X86, Mode::MODE_32) + let mut unicorn = unicorn_engine::Unicorn::new(Arch::X86, Mode::MODE_32) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); @@ -539,7 +523,7 @@ fn mem_map_ptr() { let mut mem: [u8; 4000] = [0; 4000]; let x86_code32: Vec = vec![0x41, 0x4a]; // INC ecx; DEC edx - let mut unicorn = unicorn::Unicorn::new(Arch::X86, Mode::MODE_32) + let mut unicorn = unicorn_engine::Unicorn::new(Arch::X86, Mode::MODE_32) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); @@ -619,7 +603,7 @@ fn x86_context_save_and_restore() { 0x48, 0xB8, 0xEF, 0xBE, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x05, ]; let mut unicorn = - unicorn::Unicorn::new(Arch::X86, mode).expect("failed to initialize unicorn instance"); + unicorn_engine::Unicorn::new(Arch::X86, mode).expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); assert_eq!(emu.mem_write(0x1000, &x86_code), Ok(())); @@ -636,7 +620,7 @@ fn x86_context_save_and_restore() { /* and create a new emulator, into which we will "restore" that context */ let mut unicorn2 = - unicorn::Unicorn::new(Arch::X86, mode).expect("failed to initialize unicorn instance"); + unicorn_engine::Unicorn::new(Arch::X86, mode).expect("failed to initialize unicorn instance"); let emu2 = unicorn2.borrow(); assert_eq!(emu2.context_restore(&context), Ok(())); for register in X86_REGISTERS.iter() { @@ -653,7 +637,7 @@ fn x86_context_save_and_restore() { fn x86_block_callback() { #[derive(PartialEq, Debug)] struct BlockExpectation(u64, u32); - let expects = vec![BlockExpectation(0x1000, 2), BlockExpectation(0x1000, 2)]; + let expects = vec![BlockExpectation(0x1000, 2)]; let blocks: Vec = Vec::new(); let blocks_cell = Rc::new(RefCell::new(blocks)); @@ -665,7 +649,7 @@ fn x86_block_callback() { let x86_code32: Vec = vec![0x41, 0x4a]; // INC ecx; DEC edx - let mut unicorn = unicorn::Unicorn::new(Arch::X86, Mode::MODE_32) + let mut unicorn = unicorn_engine::Unicorn::new(Arch::X86, Mode::MODE_32) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/ABkexFCfphu3zIg.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/ABkexFCfphu3zIg.png deleted file mode 100644 index a82d8e16..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/ABkexFCfphu3zIg.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/DkztJcigHCdmnRp.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/DkztJcigHCdmnRp.png deleted file mode 100644 index 95f43f59..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/DkztJcigHCdmnRp.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/F3rSByYuNTGDtC1.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/F3rSByYuNTGDtC1.png deleted file mode 100644 index 4cba2735..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/F3rSByYuNTGDtC1.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/I25E9sWcJpGyax7.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/I25E9sWcJpGyax7.png deleted file mode 100644 index f4a5af72..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/I25E9sWcJpGyax7.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/IZhyWrGebA5tT4i.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/IZhyWrGebA5tT4i.png deleted file mode 100644 index 4fb5a43c..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/IZhyWrGebA5tT4i.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/K4HMijIVt6lofvT.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/K4HMijIVt6lofvT.png deleted file mode 100644 index 521dbfb7..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/K4HMijIVt6lofvT.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/MbZk8KjQFqJOxmd.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/MbZk8KjQFqJOxmd.png deleted file mode 100644 index 795ed2cb..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/MbZk8KjQFqJOxmd.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/NExsavSgu4yMbBQ.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/NExsavSgu4yMbBQ.png deleted file mode 100644 index 3bd24013..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/NExsavSgu4yMbBQ.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/OVaHwelNQ4tcLmo.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/OVaHwelNQ4tcLmo.png deleted file mode 100644 index 05bd9d8b..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/OVaHwelNQ4tcLmo.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/YCMNcEVyX8GHoPb.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/YCMNcEVyX8GHoPb.png deleted file mode 100644 index 0268295b..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/YCMNcEVyX8GHoPb.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/ZtRKvUoaPTlshJ4.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/ZtRKvUoaPTlshJ4.png deleted file mode 100644 index 37c505c4..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/ZtRKvUoaPTlshJ4.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/aU1lbmxMjXA5g3K.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/aU1lbmxMjXA5g3K.png deleted file mode 100644 index 130e7a85..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/aU1lbmxMjXA5g3K.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/bpu4r8hgzUvO7Pm.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/bpu4r8hgzUvO7Pm.png deleted file mode 100644 index a5df3cb9..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/bpu4r8hgzUvO7Pm.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/dqKBwAWUL7XvypE.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/dqKBwAWUL7XvypE.png deleted file mode 100644 index b0532166..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/dqKBwAWUL7XvypE.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/fOnNpSKvjYyc7QB.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/fOnNpSKvjYyc7QB.png deleted file mode 100644 index 382c4401..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/fOnNpSKvjYyc7QB.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/iyodlNFY7hHEOgS.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/iyodlNFY7hHEOgS.png deleted file mode 100644 index 90d7bf94..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/iyodlNFY7hHEOgS.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/juNPWvwGUlraKRh.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/juNPWvwGUlraKRh.png deleted file mode 100644 index 83a3baa1..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/juNPWvwGUlraKRh.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/kbrF7NdV6LDxnYI.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/kbrF7NdV6LDxnYI.png deleted file mode 100644 index c7e5bd4d..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/kbrF7NdV6LDxnYI.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/l1AhdxgKE2U3tZB.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/l1AhdxgKE2U3tZB.png deleted file mode 100644 index 24e592ad..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/l1AhdxgKE2U3tZB.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/l4HhgDzcJIVvFNU.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/l4HhgDzcJIVvFNU.png deleted file mode 100644 index 475ac915..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/l4HhgDzcJIVvFNU.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/q3JtOQRPl5xTFKp.png b/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/q3JtOQRPl5xTFKp.png deleted file mode 100644 index 258d275b..00000000 Binary files a/docs/Micro Unicorn-Engine API Documentation/API_Doc_Pic/q3JtOQRPl5xTFKp.png and /dev/null differ diff --git a/docs/Micro Unicorn-Engine API Documentation/Micro Unicorn-Engine API Documentation.md b/docs/Micro Unicorn-Engine API Documentation/Micro Unicorn-Engine API Documentation.md deleted file mode 100644 index a3c8d68e..00000000 --- a/docs/Micro Unicorn-Engine API Documentation/Micro Unicorn-Engine API Documentation.md +++ /dev/null @@ -1,2717 +0,0 @@ -# Micro Unicorn-Engine API Documentation - -**Warning:** ***This is an unofficial API document by [kabeor](https://github.com/kabeor), If there are any mistakes, welcome to ask.*** - -**注意:** ***这是由kabeor制作的非官方API参考文档,如有错误欢迎提出,觉得不错可以给个star鼓励我*** - -之前对Capstone反汇编引擎的API分析文档已经被[官方](http://www.capstone-engine.org/documentation.html)收录 https://github.com/kabeor/Micro-Capstone-Engine-API-Documentation ,在实现自己想要做出的调试器的路上,又遇到了与Capstone同作者的国外大佬aquynh的另一个著名项目Unicorn,不巧的是,详尽的API文档仍然较少,更多的是大篇幅的代码,因此决定继续分析Unicorn框架,包括数据类型,已开放API及其实现。 - -Unicorn是一个轻量级, 多平台, 多架构的CPU模拟器框架,基于qemu开发,它可以代替CPU模拟代码的执行,常用于恶意代码分析,Fuzz等,该项目被用于Radare2逆向分析框架,GEF(gdb的pwn分析插件),Pwndbg,Angr符号执行框架等多个著名项目。接下来我也将通过阅读源码和代码实际调用来写一个简单的非官方版本的API手册。 - -Blog: kabeor.cn - -## 0x0 开发准备 - -Unicorn官网: http://www.unicorn-engine.org - -### 自行编译lib和dll方法 - -源码: https://github.com/unicorn-engine/unicorn/archive/master.zip - -下载后解压 - -文件结构如下: - -``` -. <- 主要引擎core engine + README + 编译文档COMPILE.TXT 等 -├── arch <- 各语言反编译支持的代码实现 -├── bindings <- 中间件 -│ ├── dotnet <- .Net 中间件 + 测试代码 -│ ├── go <- go 中间件 + 测试代码 -│ ├── haskell <- Haskell 中间件 + 测试代码 -│ ├── java <- Java 中间件 + 测试代码 -│ ├── pascal <- Pascal 中间件 + 测试代码 -│ ├── python <- Python 中间件 + 测试代码 -│ ├── ruby <- Ruby 中间件 + 测试代码 -│ └── vb6 <- VB6 中间件 + 测试代码 -├── docs <- 文档,主要是Unicorn的实现思路 -├── include <- C头文件 -├── msvc <- Microsoft Visual Studio 支持(Windows) -├── qemu <- qemu框架源码 -├── samples <- Unicorn使用示例 -└── tests <- C语言测试用例 -``` - -下面演示Windows10使用Visual Studio2019编译 - -打开msvc文件夹,内部结构如下 - -![image.png](API_Doc_Pic/iyodlNFY7hHEOgS.png) - -VS打开unicorn.sln项目文件,解决方案自动载入这些 - -![image.png](API_Doc_Pic/fOnNpSKvjYyc7QB.png) - -如果都需要的话,直接编译就好了,只需要其中几种,则右键解决方案->属性->配置属性 如下 - -![image.png](API_Doc_Pic/F3rSByYuNTGDtC1.png) - -生成选项中勾选你需要的支持项即可 - -项目编译属性为: -1. 使用多字节字符集 -2. 不使用预编译头 -3. 附加选项 /wd4018 /wd4244 /wd4267 -4. 预处理器定义中添加 ` _CRT_SECURE_NO_WARNINGS` - -编译后会在当前文件夹Debug目录下生成unicorn.lib静态编译库和unicorn.dll动态库这样就可以开始使用Unicorn进行开发了 - -编译到最后一项可能会报错系统找不到指定的路径,查看makefile发现问题出现在此处 -![image.png](API_Doc_Pic/YCMNcEVyX8GHoPb.png) - -事实上只不过是不能将生成的lib和dll复制到新建的文件夹而已,只需要到生成目录去找即可。 - -官方目前提供的最新已编译版本为1.0.1版本,比较老,建议自己编辑最新版本源码,以获得更多可用API。 -Win32:https://github.com/unicorn-engine/unicorn/releases/download/1.0.1/unicorn-1.0.1-win32.zip -Win64:https://github.com/unicorn-engine/unicorn/releases/download/1.0.1/unicorn-1.0.1-win64.zip - -**注意: 选x32或x64将影响后面开发的位数** - - - -### 引擎调用测试 - -新建一个VS项目,将..\unicorn-master\include\unicorn中的头文件以及编译好的lib和dll文件全部拷贝到新建项目的主目录下 - -![image.png](API_Doc_Pic/I25E9sWcJpGyax7.png) - -在VS解决方案中,头文件添加现有项unicorn.h,资源文件中添加unicorn.lib,重新生成解决方案 - -![image.png](API_Doc_Pic/OVaHwelNQ4tcLmo.png) - -接下来测试我们生成的unicorn框架 - -主文件代码如下 - -```cpp -#include -#include "unicorn/unicorn.h" - -// 要模拟的指令 -#define X86_CODE32 "\x41\x4a" // INC ecx; DEC edx - -// 起始地址 -#define ADDRESS 0x1000000 - -int main() -{ - uc_engine* uc; - uc_err err; - int r_ecx = 0x1234; // ECX 寄存器 - int r_edx = 0x7890; // EDX 寄存器 - - printf("Emulate i386 code\n"); - - // X86-32bit 模式初始化模拟 - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_open() with error returned: %u\n", err); - return -1; - } - - // 给模拟器申请 2MB 内存 - uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); - - // 将要模拟的指令写入内存 - if (uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1)) { - printf("Failed to write emulation code to memory, quit!\n"); - return -1; - } - - // 初始化寄存器 - uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); - uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); - - printf(">>> ECX = 0x%x\n", r_ecx); - printf(">>> EDX = 0x%x\n", r_edx); - - // 模拟代码 - err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); - if (err) { - printf("Failed on uc_emu_start() with error returned %u: %s\n", - err, uc_strerror(err)); - } - - // 打印寄存器值 - printf("Emulation done. Below is the CPU context\n"); - - uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); - uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); - printf(">>> ECX = 0x%x\n", r_ecx); - printf(">>> EDX = 0x%x\n", r_edx); - - uc_close(uc); - - return 0; -} -``` - -运行结果如下 - -![image.png](API_Doc_Pic/bpu4r8hgzUvO7Pm.png) - -ecx+1和edx-1成功模拟。 - -## 0x1 数据类型分析 - -### uc_arch - -架构选择 - -```cpp -typedef enum uc_arch { - UC_ARCH_ARM = 1, // ARM 架构 (包括 Thumb, Thumb-2) - UC_ARCH_ARM64, // ARM-64, 也称 AArch64 - UC_ARCH_MIPS, // Mips 架构 - UC_ARCH_X86, // X86 架构 (包括 x86 & x86-64) - UC_ARCH_PPC, // PowerPC 架构 (暂不支持) - UC_ARCH_SPARC, // Sparc 架构 - UC_ARCH_M68K, // M68K 架构 - UC_ARCH_MAX, -} uc_arch; -``` - - - -### uc_mode - -模式选择 - -```cpp -typedef enum uc_mode { - UC_MODE_LITTLE_ENDIAN = 0, // 小端序模式 (默认) - UC_MODE_BIG_ENDIAN = 1 << 30, // 大端序模式 - - // arm / arm64 - UC_MODE_ARM = 0, // ARM 模式 - UC_MODE_THUMB = 1 << 4, // THUMB 模式 (包括 Thumb-2) - UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M 系列 (暂不支持) - UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (暂不支持) - - // arm (32bit) cpu 类型 - UC_MODE_ARM926 = 1 << 7, // ARM926 CPU 类型 - UC_MODE_ARM946 = 1 << 8, // ARM946 CPU 类型 - UC_MODE_ARM1176 = 1 << 9, // ARM1176 CPU 类型 - - // mips - UC_MODE_MICRO = 1 << 4, // MicroMips 模式 (暂不支持) - UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (暂不支持) - UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (暂不支持) - UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA - UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA - - // x86 / x64 - UC_MODE_16 = 1 << 1, // 16-bit 模式 - UC_MODE_32 = 1 << 2, // 32-bit 模式 - UC_MODE_64 = 1 << 3, // 64-bit 模式 - - // ppc - UC_MODE_PPC32 = 1 << 2, // 32-bit 模式 (暂不支持) - UC_MODE_PPC64 = 1 << 3, // 64-bit 模式 (暂不支持) - UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions 模式 (暂不支持) - - // sparc - UC_MODE_SPARC32 = 1 << 2, // 32-bit 模式 - UC_MODE_SPARC64 = 1 << 3, // 64-bit 模式 - UC_MODE_V9 = 1 << 4, // SparcV9 模式 (暂不支持) - - // m68k -} uc_mode; -``` - - - -### uc_err - -错误类型,是uc_errno()的返回值 - -```cpp -typedef enum uc_err { - UC_ERR_OK = 0, // 无错误 - UC_ERR_NOMEM, // 内存不足: uc_open(), uc_emulate() - UC_ERR_ARCH, // 不支持的架构: uc_open() - UC_ERR_HANDLE, // 不可用句柄 - UC_ERR_MODE, // 不可用/不支持架构: uc_open() - UC_ERR_VERSION, // 不支持版本 (中间件) - UC_ERR_READ_UNMAPPED, // 由于在未映射的内存上读取而退出模拟: uc_emu_start() - UC_ERR_WRITE_UNMAPPED, // 由于在未映射的内存上写入而退出模拟: uc_emu_start() - UC_ERR_FETCH_UNMAPPED, // 由于在未映射的内存中获取数据而退出模拟: uc_emu_start() - UC_ERR_HOOK, // 无效的hook类型: uc_hook_add() - UC_ERR_INSN_INVALID, // 由于指令无效而退出模拟: uc_emu_start() - UC_ERR_MAP, // 无效的内存映射: uc_mem_map() - UC_ERR_WRITE_PROT, // 由于UC_MEM_WRITE_PROT冲突而停止模拟: uc_emu_start() - UC_ERR_READ_PROT, // 由于UC_MEM_READ_PROT冲突而停止模拟: uc_emu_start() - UC_ERR_FETCH_PROT, // 由于UC_MEM_FETCH_PROT冲突而停止模拟: uc_emu_start() - UC_ERR_ARG, // 提供给uc_xxx函数的无效参数 - UC_ERR_READ_UNALIGNED, // 未对齐读取 - UC_ERR_WRITE_UNALIGNED, // 未对齐写入 - UC_ERR_FETCH_UNALIGNED, // 未对齐的提取 - UC_ERR_HOOK_EXIST, // 此事件的钩子已经存在 - UC_ERR_RESOURCE, // 资源不足: uc_emu_start() - UC_ERR_EXCEPTION, // 未处理的CPU异常 - UC_ERR_TIMEOUT // 模拟超时 -} uc_err; -``` - - - -### uc_mem_type - -UC_HOOK_MEM_*的所有内存访问类型 - -```cpp -typedef enum uc_mem_type { - UC_MEM_READ = 16, // 内存从..读取 - UC_MEM_WRITE, // 内存写入到.. - UC_MEM_FETCH, // 内存被获取 - UC_MEM_READ_UNMAPPED, // 未映射内存从..读取 - UC_MEM_WRITE_UNMAPPED, // 未映射内存写入到.. - UC_MEM_FETCH_UNMAPPED, // 未映射内存被获取 - UC_MEM_WRITE_PROT, // 内存写保护,但是已映射 - UC_MEM_READ_PROT, // 内存读保护,但是已映射 - UC_MEM_FETCH_PROT, // 内存不可执行,但是已映射 - UC_MEM_READ_AFTER, // 内存从 (成功访问的地址) 读入 -} uc_mem_type; -``` - - - -### uc_hook_type - -uc_hook_add()的所有hook类型参数 - -```cpp -typedef enum uc_hook_type { - // Hook 所有中断/syscall 事件 - UC_HOOK_INTR = 1 << 0, - // Hook 一条特定的指令 - 只支持非常小的指令子集 - UC_HOOK_INSN = 1 << 1, - // Hook 一段代码 - UC_HOOK_CODE = 1 << 2, - // Hook 基本块 - UC_HOOK_BLOCK = 1 << 3, - // 用于在未映射的内存上读取内存的Hook - UC_HOOK_MEM_READ_UNMAPPED = 1 << 4, - // Hook 无效的内存写事件 - UC_HOOK_MEM_WRITE_UNMAPPED = 1 << 5, - // Hook 执行事件的无效内存 - UC_HOOK_MEM_FETCH_UNMAPPED = 1 << 6, - // Hook 读保护的内存 - UC_HOOK_MEM_READ_PROT = 1 << 7, - // Hook 写保护的内存 - UC_HOOK_MEM_WRITE_PROT = 1 << 8, - // Hook 不可执行内存上的内存 - UC_HOOK_MEM_FETCH_PROT = 1 << 9, - // Hook 内存读取事件 - UC_HOOK_MEM_READ = 1 << 10, - // Hook 内存写入事件 - UC_HOOK_MEM_WRITE = 1 << 11, - // Hook 内存获取执行事件 - UC_HOOK_MEM_FETCH = 1 << 12, - // Hook 内存读取事件,只允许能成功访问的地址 - // 成功读取后将触发回调 - UC_HOOK_MEM_READ_AFTER = 1 << 13, - // Hook 无效指令异常 - UC_HOOK_INSN_INVALID = 1 << 14, -} uc_hook_type; -``` - - - -### 宏定义Hook类型 - -```cpp -// Hook 所有未映射内存访问的事件 -#define UC_HOOK_MEM_UNMAPPED (UC_HOOK_MEM_READ_UNMAPPED + UC_HOOK_MEM_WRITE_UNMAPPED + UC_HOOK_MEM_FETCH_UNMAPPED) -// Hook 所有对受保护内存的非法访问事件 -#define UC_HOOK_MEM_PROT (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_FETCH_PROT) -// Hook 所有非法读取存储器的事件 -#define UC_HOOK_MEM_READ_INVALID (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_READ_UNMAPPED) -// Hook 所有非法写入存储器的事件 -#define UC_HOOK_MEM_WRITE_INVALID (UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_WRITE_UNMAPPED) -// Hook 所有非法获取内存的事件 -#define UC_HOOK_MEM_FETCH_INVALID (UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_UNMAPPED) -// Hook 所有非法的内存访问事件 -#define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_UNMAPPED + UC_HOOK_MEM_PROT) -// Hook 所有有效内存访问的事件 -// 注意: UC_HOOK_MEM_READ 在 UC_HOOK_MEM_READ_PROT 和 UC_HOOK_MEM_READ_UNMAPPED 之前触发 , -// 因此这个Hook可能会触发一些无效的读取。 -#define UC_HOOK_MEM_VALID (UC_HOOK_MEM_READ + UC_HOOK_MEM_WRITE + UC_HOOK_MEM_FETCH) -``` - - - -### uc_mem_region - -由uc_mem_map()和uc_mem_map_ptr()映射内存区域 -使用uc_mem_regions()检索该内存区域的列表 - -```cpp -typedef struct uc_mem_region { - uint64_t begin; // 区域起始地址 (包括) - uint64_t end; // 区域结束地址 (包括) - uint32_t perms; // 区域的内存权限 -} uc_mem_region; -``` - - - -### uc_query_type - -uc_query()的所有查询类型参数 - -```cpp -typedef enum uc_query_type { - // 动态查询当前硬件模式 - UC_QUERY_MODE = 1, - UC_QUERY_PAGE_SIZE, - UC_QUERY_ARCH, -} uc_query_type; -``` - - - -### uc_context - -与uc_context_*()一起使用,管理CPU上下文的不透明存储 - -```cpp -struct uc_context; -typedef struct uc_context uc_context; -``` - - - -### uc_prot - -新映射区域的权限 - -```cpp -typedef enum uc_prot { - UC_PROT_NONE = 0, //无 - UC_PROT_READ = 1, //读取 - UC_PROT_WRITE = 2, //写入 - UC_PROT_EXEC = 4, //可执行 - UC_PROT_ALL = 7, //所有权限 -} uc_prot; -``` - - - -## 0x2 API分析 - -### uc_version - -```cpp -unsigned int uc_version(unsigned int *major, unsigned int *minor); -``` - -用于返回Unicorn API主次版本信息 - -``` -@major: API主版本号 -@minor: API次版本号 -@return 16进制数,计算方式 (major << 8 | minor) - -提示: 该返回值可以和宏UC_MAKE_VERSION比较 -``` - -源码实现 - -```c -unsigned int uc_version(unsigned int *major, unsigned int *minor) -{ - if (major != NULL && minor != NULL) { - *major = UC_API_MAJOR; //宏 - *minor = UC_API_MINOR; //宏 - } - - return (UC_API_MAJOR << 8) + UC_API_MINOR; //(major << 8 | minor) -} -``` - -编译后不可更改,不接受自定义版本 - -使用示例: - -```cpp -#include -#include "unicorn/unicorn.h" -using namespace std; - -int main() -{ - unsigned int version; - version = uc_version(NULL,NULL); - cout << hex << version << endl; - return 0; -} -``` - -输出: - -![image.png](API_Doc_Pic/q3JtOQRPl5xTFKp.png) - -得到版本号1.0.0 - - - -### uc_arch_supported - -```c -bool uc_arch_supported(uc_arch arch); -``` - -确定Unicorn是否支持当前架构 - -``` - @arch: 架构类型 (UC_ARCH_*) - @return 如果支持返回True -``` - -源码实现 - -```c -bool uc_arch_supported(uc_arch arch) -{ - switch (arch) { -#ifdef UNICORN_HAS_ARM - case UC_ARCH_ARM: return true; -#endif -#ifdef UNICORN_HAS_ARM64 - case UC_ARCH_ARM64: return true; -#endif -#ifdef UNICORN_HAS_M68K - case UC_ARCH_M68K: return true; -#endif -#ifdef UNICORN_HAS_MIPS - case UC_ARCH_MIPS: return true; -#endif -#ifdef UNICORN_HAS_PPC - case UC_ARCH_PPC: return true; -#endif -#ifdef UNICORN_HAS_SPARC - case UC_ARCH_SPARC: return true; -#endif -#ifdef UNICORN_HAS_X86 - case UC_ARCH_X86: return true; -#endif - /* 无效或禁用架构 */ - default: return false; - } -} -``` - -使用示例: - -```cpp -#include -#include "unicorn/unicorn.h" -using namespace std; - -int main() -{ - cout << "是否支持UC_ARCH_X86架构:" << uc_arch_supported(UC_ARCH_X86) << endl; - return 0; -} -``` - -输出: - -![image.png](API_Doc_Pic/NExsavSgu4yMbBQ.png) - - - -### uc_open - -```c -uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc); -``` - -创建新的Unicorn实例 - -``` -@arch: 架构类型 (UC_ARCH_*) -@mode: 硬件模式. 由 UC_MODE_* 组合 -@uc: 指向 uc_engine 的指针, 返回时更新 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) -{ - struct uc_struct *uc; - - if (arch < UC_ARCH_MAX) { - uc = calloc(1, sizeof(*uc)); //申请内存 - if (!uc) { - // 内存不足 - return UC_ERR_NOMEM; - } - - uc->errnum = UC_ERR_OK; - uc->arch = arch; - uc->mode = mode; - - // 初始化 - // uc->ram_list = { .blocks = QTAILQ_HEAD_INITIALIZER(ram_list.blocks) }; - uc->ram_list.blocks.tqh_first = NULL; - uc->ram_list.blocks.tqh_last = &(uc->ram_list.blocks.tqh_first); - - uc->memory_listeners.tqh_first = NULL; - uc->memory_listeners.tqh_last = &uc->memory_listeners.tqh_first; - - uc->address_spaces.tqh_first = NULL; - uc->address_spaces.tqh_last = &uc->address_spaces.tqh_first; - - switch(arch) { // 根据架构进行预处理 - default: - break; -#ifdef UNICORN_HAS_M68K - case UC_ARCH_M68K: - if ((mode & ~UC_MODE_M68K_MASK) || - !(mode & UC_MODE_BIG_ENDIAN)) { - free(uc); - return UC_ERR_MODE; - } - uc->init_arch = m68k_uc_init; - break; -#endif -#ifdef UNICORN_HAS_X86 - case UC_ARCH_X86: - if ((mode & ~UC_MODE_X86_MASK) || - (mode & UC_MODE_BIG_ENDIAN) || - !(mode & (UC_MODE_16|UC_MODE_32|UC_MODE_64))) { - free(uc); - return UC_ERR_MODE; - } - uc->init_arch = x86_uc_init; - break; -#endif -#ifdef UNICORN_HAS_ARM - case UC_ARCH_ARM: - if ((mode & ~UC_MODE_ARM_MASK)) { - free(uc); - return UC_ERR_MODE; - } - if (mode & UC_MODE_BIG_ENDIAN) { - uc->init_arch = armeb_uc_init; - } else { - uc->init_arch = arm_uc_init; - } - - if (mode & UC_MODE_THUMB) - uc->thumb = 1; - break; -#endif -#ifdef UNICORN_HAS_ARM64 - case UC_ARCH_ARM64: - if (mode & ~UC_MODE_ARM_MASK) { - free(uc); - return UC_ERR_MODE; - } - if (mode & UC_MODE_BIG_ENDIAN) { - uc->init_arch = arm64eb_uc_init; - } else { - uc->init_arch = arm64_uc_init; - } - break; -#endif - -#if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL) - case UC_ARCH_MIPS: - if ((mode & ~UC_MODE_MIPS_MASK) || - !(mode & (UC_MODE_MIPS32|UC_MODE_MIPS64))) { - free(uc); - return UC_ERR_MODE; - } - if (mode & UC_MODE_BIG_ENDIAN) { -#ifdef UNICORN_HAS_MIPS - if (mode & UC_MODE_MIPS32) - uc->init_arch = mips_uc_init; -#endif -#ifdef UNICORN_HAS_MIPS64 - if (mode & UC_MODE_MIPS64) - uc->init_arch = mips64_uc_init; -#endif - } else { // 小端序 -#ifdef UNICORN_HAS_MIPSEL - if (mode & UC_MODE_MIPS32) - uc->init_arch = mipsel_uc_init; -#endif -#ifdef UNICORN_HAS_MIPS64EL - if (mode & UC_MODE_MIPS64) - uc->init_arch = mips64el_uc_init; -#endif - } - break; -#endif - -#ifdef UNICORN_HAS_SPARC - case UC_ARCH_SPARC: - if ((mode & ~UC_MODE_SPARC_MASK) || - !(mode & UC_MODE_BIG_ENDIAN) || - !(mode & (UC_MODE_SPARC32|UC_MODE_SPARC64))) { - free(uc); - return UC_ERR_MODE; - } - if (mode & UC_MODE_SPARC64) - uc->init_arch = sparc64_uc_init; - else - uc->init_arch = sparc_uc_init; - break; -#endif - } - - if (uc->init_arch == NULL) { - return UC_ERR_ARCH; - } - - if (machine_initialize(uc)) - return UC_ERR_RESOURCE; - - *result = uc; - - if (uc->reg_reset) - uc->reg_reset(uc); - - return UC_ERR_OK; - } else { - return UC_ERR_ARCH; - } -} -``` - -**注意: uc_open会申请堆内存,使用完必须用uc_close释放,否则会发生泄露** - -使用示例: - -```cpp -#include -#include "unicorn/unicorn.h" -using namespace std; - -int main() -{ - uc_engine* uc; - uc_err err; - - //// 初始化 X86-32bit 模式模拟器 - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_open() with error returned: %u\n", err); - return -1; - } - - if (!err) - cout << "uc引擎创建成功" << endl; - - //// 关闭uc - err = uc_close(uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_close() with error returned: %u\n", err); - return -1; - } - - if (!err) - cout << "uc引擎关闭成功" << endl; - - return 0; -} -``` - -输出 - -![image.png](API_Doc_Pic/dqKBwAWUL7XvypE.png) - - - -### uc_close - -```c -uc_err uc_close(uc_engine *uc); -``` - -关闭一个uc实例,将释放内存。关闭后无法恢复。 - -``` -@uc: 指向由 uc_open() 返回的指针 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_close(uc_engine *uc) -{ - int i; - struct list_item *cur; - struct hook *hook; - - // 清理内部数据 - if (uc->release) - uc->release(uc->tcg_ctx); - g_free(uc->tcg_ctx); - - // 清理 CPU. - g_free(uc->cpu->tcg_as_listener); - g_free(uc->cpu->thread); - - // 清理所有 objects. - OBJECT(uc->machine_state->accelerator)->ref = 1; - OBJECT(uc->machine_state)->ref = 1; - OBJECT(uc->owner)->ref = 1; - OBJECT(uc->root)->ref = 1; - - object_unref(uc, OBJECT(uc->machine_state->accelerator)); - object_unref(uc, OBJECT(uc->machine_state)); - object_unref(uc, OBJECT(uc->cpu)); - object_unref(uc, OBJECT(&uc->io_mem_notdirty)); - object_unref(uc, OBJECT(&uc->io_mem_unassigned)); - object_unref(uc, OBJECT(&uc->io_mem_rom)); - object_unref(uc, OBJECT(uc->root)); - - // 释放内存 - g_free(uc->system_memory); - - // 释放相关线程 - if (uc->qemu_thread_data) - g_free(uc->qemu_thread_data); - - // 释放其他数据 - free(uc->l1_map); - - if (uc->bounce.buffer) { - free(uc->bounce.buffer); - } - - g_hash_table_foreach(uc->type_table, free_table, uc); - g_hash_table_destroy(uc->type_table); - - for (i = 0; i < DIRTY_MEMORY_NUM; i++) { - free(uc->ram_list.dirty_memory[i]); - } - - // 释放hook和hook列表 - for (i = 0; i < UC_HOOK_MAX; i++) { - cur = uc->hook[i].head; - // hook 可存在于多个列表,可通过计数获取释放的时间 - while (cur) { - hook = (struct hook *)cur->data; - if (--hook->refs == 0) { - free(hook); - } - cur = cur->next; - } - list_clear(&uc->hook[i]); - } - - free(uc->mapped_blocks); - - // 最后释放uc自身 - memset(uc, 0, sizeof(*uc)); - free(uc); - - return UC_ERR_OK; -} -``` - -使用实例同uc_open() - - - -### uc_query - -```c -uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result); -``` - -查询引擎的内部状态 - -``` - @uc: uc_open() 返回的句柄 - @type: uc_query_type 中枚举的类型 - - @result: 保存被查询的内部状态的指针 - - @return: 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result) -{ - if (type == UC_QUERY_PAGE_SIZE) { - *result = uc->target_page_size; - return UC_ERR_OK; - } - - if (type == UC_QUERY_ARCH) { - *result = uc->arch; - return UC_ERR_OK; - } - - switch(uc->arch) { -#ifdef UNICORN_HAS_ARM - case UC_ARCH_ARM: - return uc->query(uc, type, result); -#endif - default: - return UC_ERR_ARG; - } - - return UC_ERR_OK; -} -``` - -使用示例: - -```cpp -#include -#include "unicorn/unicorn.h" -using namespace std; -int main() -{ - uc_engine* uc; - uc_err err; - - //// Initialize emulator in X86-32bit mode - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_open() with error returned: %u\n", err); - return -1; - } - if (!err) - cout << "uc实例创建成功" << endl; - - size_t result[] = {0}; - err = uc_query(uc, UC_QUERY_ARCH, result); // 查询架构 - if (!err) - cout << "查询成功: " << *result << endl; - - err = uc_close(uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_close() with error returned: %u\n", err); - return -1; - } - if (!err) - cout << "uc实例关闭成功" << endl; - - return 0; -} -``` - -输出 - -![image.png](API_Doc_Pic/ZtRKvUoaPTlshJ4.png) - -架构查询结果为4,对应的正是UC_ARCH_X86 - - - -### uc_errno - -```c -uc_err uc_errno(uc_engine *uc); -``` - -当某个API函数失败时,报告最后的错误号,一旦被访问,uc_errno可能不会保留原来的值。 - -``` -@uc: uc_open() 返回的句柄 - -@return: 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_errno(uc_engine *uc) -{ - return uc->errnum; -} -``` - -使用示例: - -```cpp -#include -#include "unicorn/unicorn.h" -using namespace std; - -int main() -{ - uc_engine* uc; - uc_err err; - - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_open() with error returned: %u\n", err); - return -1; - } - if (!err) - cout << "uc实例创建成功" << endl; - - err = uc_errno(uc); - cout << "错误号: " << err << endl; - - err = uc_close(uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_close() with error returned: %u\n", err); - return -1; - } - if (!err) - cout << "uc实例关闭成功" << endl; - - return 0; -} -``` - -输出 - -![image.png](API_Doc_Pic/IZhyWrGebA5tT4i.png) - -无错误,输出错误号为0 - - - -### uc_strerror - -```c -const char *uc_strerror(uc_err code); -``` - -返回给定错误号的解释 - -``` - @code: 错误号 - - @return: 指向给定错误号的解释的字符串指针 -``` - -源码实现 - -```cpp -const char *uc_strerror(uc_err code) -{ - switch(code) { - default: - return "Unknown error code"; - case UC_ERR_OK: - return "OK (UC_ERR_OK)"; - case UC_ERR_NOMEM: - return "No memory available or memory not present (UC_ERR_NOMEM)"; - case UC_ERR_ARCH: - return "Invalid/unsupported architecture (UC_ERR_ARCH)"; - case UC_ERR_HANDLE: - return "Invalid handle (UC_ERR_HANDLE)"; - case UC_ERR_MODE: - return "Invalid mode (UC_ERR_MODE)"; - case UC_ERR_VERSION: - return "Different API version between core & binding (UC_ERR_VERSION)"; - case UC_ERR_READ_UNMAPPED: - return "Invalid memory read (UC_ERR_READ_UNMAPPED)"; - case UC_ERR_WRITE_UNMAPPED: - return "Invalid memory write (UC_ERR_WRITE_UNMAPPED)"; - case UC_ERR_FETCH_UNMAPPED: - return "Invalid memory fetch (UC_ERR_FETCH_UNMAPPED)"; - case UC_ERR_HOOK: - return "Invalid hook type (UC_ERR_HOOK)"; - case UC_ERR_INSN_INVALID: - return "Invalid instruction (UC_ERR_INSN_INVALID)"; - case UC_ERR_MAP: - return "Invalid memory mapping (UC_ERR_MAP)"; - case UC_ERR_WRITE_PROT: - return "Write to write-protected memory (UC_ERR_WRITE_PROT)"; - case UC_ERR_READ_PROT: - return "Read from non-readable memory (UC_ERR_READ_PROT)"; - case UC_ERR_FETCH_PROT: - return "Fetch from non-executable memory (UC_ERR_FETCH_PROT)"; - case UC_ERR_ARG: - return "Invalid argument (UC_ERR_ARG)"; - case UC_ERR_READ_UNALIGNED: - return "Read from unaligned memory (UC_ERR_READ_UNALIGNED)"; - case UC_ERR_WRITE_UNALIGNED: - return "Write to unaligned memory (UC_ERR_WRITE_UNALIGNED)"; - case UC_ERR_FETCH_UNALIGNED: - return "Fetch from unaligned memory (UC_ERR_FETCH_UNALIGNED)"; - case UC_ERR_RESOURCE: - return "Insufficient resource (UC_ERR_RESOURCE)"; - case UC_ERR_EXCEPTION: - return "Unhandled CPU exception (UC_ERR_EXCEPTION)"; - case UC_ERR_TIMEOUT: - return "Emulation timed out (UC_ERR_TIMEOUT)"; - } -} -``` - -使用示例: - -```cpp -#include -#include "unicorn/unicorn.h" -using namespace std; - -int main() -{ - uc_engine* uc; - uc_err err; - - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_open() with error returned: %u\n", err); - return -1; - } - if (!err) - cout << "uc实例创建成功" << endl; - - err = uc_errno(uc); - cout << "错误号: " << err << " 错误描述: " << uc_strerror(err) <reg_write) - ret = uc->reg_write(uc, (unsigned int *)ids, vals, count); //结构体中写入 - else - return UC_ERR_EXCEPTION; - - return ret; -} -``` - -使用示例: - -```cpp -#include -#include "unicorn/unicorn.h" -using namespace std; - -int main() -{ - uc_engine* uc; - uc_err err; - - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_open() with error returned: %u\n", err); - return -1; - } - if (!err) - cout << "uc实例创建成功" << endl; - - int r_eax = 0x12; - err = uc_reg_write(uc, UC_X86_REG_ECX, &r_eax); - if (!err) - cout << "写入成功: " << r_eax << endl; - - err = uc_close(uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_close() with error returned: %u\n", err); - return -1; - } - if (!err) - cout << "uc实例关闭成功" << endl; - - return 0; -} -``` - -输出 - -![image.png](API_Doc_Pic/DkztJcigHCdmnRp.png) - - - -### uc_reg_read - -```c -uc_err uc_reg_read(uc_engine *uc, int regid, void *value); -``` - -读取寄存器的值 - -``` -@uc: uc_open()返回的句柄 -@regid: 将被读取的寄存器ID -@value: 指向保存寄存器值的指针 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_reg_read(uc_engine *uc, int regid, void *value) -{ - return uc_reg_read_batch(uc, ®id, &value, 1); -} - -uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count) -{ - if (uc->reg_read) - uc->reg_read(uc, (unsigned int *)ids, vals, count); - else - return -1; - - return UC_ERR_OK; -} -``` - -使用示例: - -```cpp -#include -#include "unicorn/unicorn.h" -using namespace std; - -int main() -{ - uc_engine* uc; - uc_err err; - - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_open() with error returned: %u\n", err); - return -1; - } - if (!err) - cout << "uc实例创建成功" << endl; - - int r_eax = 0x12; - err = uc_reg_write(uc, UC_X86_REG_ECX, &r_eax); - if (!err) - cout << "写入成功: " << r_eax << endl; - - int recv_eax; - err = uc_reg_read(uc, UC_X86_REG_ECX, &recv_eax); - if (!err) - cout << "读取成功: " << recv_eax << endl; - - err = uc_close(uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_close() with error returned: %u\n", err); - return -1; - } - if (!err) - cout << "uc实例关闭成功" << endl; - - return 0; -} -``` - -输出 - -![image.png](API_Doc_Pic/ABkexFCfphu3zIg.png) - - - -### uc_reg_write_batch - -```c -uc_err uc_reg_write_batch(uc_engine *uc, int *regs, void *const *vals, int count); -``` - -同时将多个值写入多个寄存器 - -``` -@uc: uc_open()返回的句柄 -@regid: 存储将被写入的多个寄存器ID的数组 -@value: 指向保存多个值的数组的指针 -@count: *regs 和 *vals 数组的长度 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count) -{ - int ret = UC_ERR_OK; - if (uc->reg_write) - ret = uc->reg_write(uc, (unsigned int *)ids, vals, count); - else - return UC_ERR_EXCEPTION; - - return ret; -} -``` - -使用示例: - -```cpp -#include -#include -#include "unicorn/unicorn.h" -using namespace std; - -int syscall_abi[] = { - UC_X86_REG_RAX, UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, - UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9 -}; - -uint64_t vals[7] = { 200, 10, 11, 12, 13, 14, 15 }; - -void* ptrs[7]; - -int main() -{ - int i; - uc_err err; - uc_engine* uc; - - // set up register pointers - for (i = 0; i < 7; i++) { - ptrs[i] = &vals[i]; - } - - if ((err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc))) { - uc_perror("uc_open", err); - return 1; - } - - // reg_write_batch - printf("reg_write_batch({200, 10, 11, 12, 13, 14, 15})\n"); - if ((err = uc_reg_write_batch(uc, syscall_abi, ptrs, 7))) { - uc_perror("uc_reg_write_batch", err); - return 1; - } - - // reg_read_batch - memset(vals, 0, sizeof(vals)); - if ((err = uc_reg_read_batch(uc, syscall_abi, ptrs, 7))) { - uc_perror("uc_reg_read_batch", err); - return 1; - } - - printf("reg_read_batch = {"); - - for (i = 0; i < 7; i++) { - if (i != 0) printf(", "); - printf("%" PRIu64, vals[i]); - } - - printf("}\n"); - - uint64_t var[7] = { 0 }; - for (int i = 0; i < 7; i++) - { - cout << syscall_abi[i] << " "; - printf("%" PRIu64, vals[i]); - cout << endl; - } - - return 0; -} -``` - -输出 - -![image.png](API_Doc_Pic/l1AhdxgKE2U3tZB.png) - - - -### uc_reg_read_batch - -```c -uc_err uc_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count); -``` - -同时读取多个寄存器的值。 - -``` -@uc: uc_open()返回的句柄 -@regid: 存储将被读取的多个寄存器ID的数组 -@value: 指向保存多个值的数组的指针 -@count: *regs 和 *vals 数组的长度 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count) -{ - if (uc->reg_read) - uc->reg_read(uc, (unsigned int *)ids, vals, count); - else - return -1; - - return UC_ERR_OK; -} -``` - -使用示例同uc_reg_write_batch()。 - - - -### uc_mem_write - -```c -uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t size); -``` - -在内存中写入一段字节码。 - -``` - @uc: uc_open() 返回的句柄 - @address: 写入字节的起始地址 - @bytes: 指向一个包含要写入内存的数据的指针 - @size: 要写入的内存大小。 - - 注意: @bytes 必须足够大以包含 @size 字节。 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes, size_t size) -{ - size_t count = 0, len; - const uint8_t *bytes = _bytes; - - if (uc->mem_redirect) { - address = uc->mem_redirect(address); - } - - if (!check_mem_area(uc, address, size)) - return UC_ERR_WRITE_UNMAPPED; - - // 内存区域可以重叠相邻的内存块 - while(count < size) { - MemoryRegion *mr = memory_mapping(uc, address); - if (mr) { - uint32_t operms = mr->perms; - if (!(operms & UC_PROT_WRITE)) // 没有写保护 - // 标记为可写 - uc->readonly_mem(mr, false); - - len = (size_t)MIN(size - count, mr->end - address); - if (uc->write_mem(&uc->as, address, bytes, len) == false) - break; - - if (!(operms & UC_PROT_WRITE)) // 没有写保护 - // 设置写保护 - uc->readonly_mem(mr, true); - - count += len; - address += len; - bytes += len; - } else // 此地址尚未被映射 - break; - } - - if (count == size) - return UC_ERR_OK; - else - return UC_ERR_WRITE_UNMAPPED; -} -``` - -使用示例: - -```cpp -#include -#include -#include "unicorn/unicorn.h" -using namespace std; - -#define X86_CODE32 "\x41\x4a" // INC ecx; DEC edx -#define ADDRESS 0x1000 - -int main() -{ - uc_engine* uc; - uc_err err; - - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_open() with error returned: %u\n", err); - return -1; - } - - uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); - - if (uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1)) { - printf("Failed to write emulation code to memory, quit!\n"); - return -1; - } - - uint32_t code; - - if(uc_mem_read(uc,ADDRESS,&code, sizeof(code))) { - printf("Failed to read emulation code to memory, quit!\n"); - return -1; - } - - cout << hex << code << endl; - - err = uc_close(uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_close() with error returned: %u\n", err); - return -1; - } - return 0; -} -``` - -输出 - -![image.png](API_Doc_Pic/l4HhgDzcJIVvFNU.png) - - - -### uc_mem_read - -```c -uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size); -``` - -从内存中读取字节。 - -``` - @uc: uc_open() 返回的句柄 - @address: 读取字节的起始地址 - @bytes: 指向一个包含要读取内存的数据的指针 - @size: 要读取的内存大小。 - - 注意: @bytes 必须足够大以包含 @size 字节。 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size) -{ - size_t count = 0, len; - uint8_t *bytes = _bytes; - - if (uc->mem_redirect) { - address = uc->mem_redirect(address); - } - - if (!check_mem_area(uc, address, size)) - return UC_ERR_READ_UNMAPPED; - - // 内存区域可以重叠相邻的内存块 - while(count < size) { - MemoryRegion *mr = memory_mapping(uc, address); - if (mr) { - len = (size_t)MIN(size - count, mr->end - address); - if (uc->read_mem(&uc->as, address, bytes, len) == false) - break; - count += len; - address += len; - bytes += len; - } else // 此地址尚未被映射 - break; - } - - if (count == size) - return UC_ERR_OK; - else - return UC_ERR_READ_UNMAPPED; -} -``` - -使用示例同uc_mem_write() - - - -### uc_emu_start - -```c -uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count); -``` - -在指定的时间内模拟机器码。 - -``` -@uc: uc_open() 返回的句柄 -@begin: 开始模拟的地址 -@until: 模拟停止的地址 (当到达该地址时) -@timeout: 模拟代码的持续时间(以微秒计)。当这个值为0时,将在无限时间内模拟代码,直到代码完成。 -@count: 要模拟的指令数。当这个值为0时,将模拟所有可用的代码,直到代码完成 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) -{ - // 重制计数器 - uc->emu_counter = 0; - uc->invalid_error = UC_ERR_OK; - uc->block_full = false; - uc->emulation_done = false; - uc->timed_out = false; - - switch(uc->arch) { - default: - break; -#ifdef UNICORN_HAS_M68K - case UC_ARCH_M68K: - uc_reg_write(uc, UC_M68K_REG_PC, &begin); - break; -#endif -#ifdef UNICORN_HAS_X86 - case UC_ARCH_X86: - switch(uc->mode) { - default: - break; - case UC_MODE_16: { - uint64_t ip; - uint16_t cs; - - uc_reg_read(uc, UC_X86_REG_CS, &cs); - // 抵消后面增加的 IP 和 CS - ip = begin - cs*16; - uc_reg_write(uc, UC_X86_REG_IP, &ip); - break; - } - case UC_MODE_32: - uc_reg_write(uc, UC_X86_REG_EIP, &begin); - break; - case UC_MODE_64: - uc_reg_write(uc, UC_X86_REG_RIP, &begin); - break; - } - break; -#endif -#ifdef UNICORN_HAS_ARM - case UC_ARCH_ARM: - uc_reg_write(uc, UC_ARM_REG_R15, &begin); - break; -#endif -#ifdef UNICORN_HAS_ARM64 - case UC_ARCH_ARM64: - uc_reg_write(uc, UC_ARM64_REG_PC, &begin); - break; -#endif -#ifdef UNICORN_HAS_MIPS - case UC_ARCH_MIPS: - // TODO: MIPS32/MIPS64/BIGENDIAN etc - uc_reg_write(uc, UC_MIPS_REG_PC, &begin); - break; -#endif -#ifdef UNICORN_HAS_SPARC - case UC_ARCH_SPARC: - // TODO: Sparc/Sparc64 - uc_reg_write(uc, UC_SPARC_REG_PC, &begin); - break; -#endif - } - - uc->stop_request = false; - - uc->emu_count = count; - // 如果不需要计数,则移除计数挂钩hook - if (count <= 0 && uc->count_hook != 0) { - uc_hook_del(uc, uc->count_hook); - uc->count_hook = 0; - } - // 设置计数hook记录指令数 - if (count > 0 && uc->count_hook == 0) { - uc_err err; - // 对计数指令的回调必须在所有其他操作之前运行,因此必须在hook列表的开头插入hook,而不是附加hook - uc->hook_insert = 1; - err = uc_hook_add(uc, &uc->count_hook, UC_HOOK_CODE, hook_count_cb, NULL, 1, 0); - // 恢复到 uc_hook_add() - uc->hook_insert = 0; - if (err != UC_ERR_OK) { - return err; - } - } - - uc->addr_end = until; - - if (timeout) - enable_emu_timer(uc, timeout * 1000); // microseconds -> nanoseconds - - if (uc->vm_start(uc)) { - return UC_ERR_RESOURCE; - } - - // 模拟完成 - uc->emulation_done = true; - - if (timeout) { - // 等待超时 - qemu_thread_join(&uc->timer); - } - - if(uc->timed_out) - return UC_ERR_TIMEOUT; - - return uc->invalid_error; -} -``` - -使用示例: - -```cpp -#include -#include -#include "unicorn/unicorn.h" -using namespace std; - -#define X86_CODE32 "\x33\xC0" // xor eax, eax -#define ADDRESS 0x1000 - -int main() -{ - uc_engine* uc; - uc_err err; - - int r_eax = 0x111; - - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_open() with error returned: %u\n", err); - return -1; - } - - uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); - - if (uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1)) { - printf("Failed to write emulation code to memory, quit!\n"); - return -1; - } - - uc_reg_write(uc, UC_X86_REG_EAX, &r_eax); - printf(">>> before EAX = 0x%x\n", r_eax); - - err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); - if (err) { - printf("Failed on uc_emu_start() with error returned %u: %s\n", - err, uc_strerror(err)); - } - - uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); - printf(">>> after EAX = 0x%x\n", r_eax); - - err = uc_close(uc); - if (err != UC_ERR_OK) { - printf("Failed on uc_close() with error returned: %u\n", err); - return -1; - } - - return 0; -} -``` - -输出 - -![image.png](API_Doc_Pic/K4HMijIVt6lofvT.png) - - - -### uc_emu_stop - -```c -uc_err uc_emu_stop(uc_engine *uc); -``` - -停止模拟 - -通常是从通过 tracing API注册的回调函数中调用。 - -``` -@uc: uc_open() 返回的句柄 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_emu_stop(uc_engine *uc) -{ - if (uc->emulation_done) - return UC_ERR_OK; - - uc->stop_request = true; - - if (uc->current_cpu) { - // 退出当前线程 - cpu_exit(uc->current_cpu); - } - - return UC_ERR_OK; -} -``` - -使用示例: - -```cpp -uc_emu_stop(uc); -``` - - - -### uc_hook_add - -```c -uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, - void *user_data, uint64_t begin, uint64_t end, ...); -``` - -注册hook事件的回调,当hook事件被触发将会进行回调。 - -``` - @uc: uc_open() 返回的句柄 - @hh: 注册hook得到的句柄. uc_hook_del() 中使用 - @type: hook 类型 - @callback: 当指令被命中时要运行的回调 - @user_data: 用户自定义数据. 将被传递给回调函数的最后一个参数 @user_data - @begin: 回调生效区域的起始地址(包括) - @end: 回调生效区域的结束地址(包括) - 注意 1: 只有回调的地址在[@begin, @end]中才会调用回调 - 注意 2: 如果 @begin > @end, 每当触发此hook类型时都会调用回调 - @...: 变量参数 (取决于 @type) - 注意: 如果 @type = UC_HOOK_INSN, 这里是指令ID (如: UC_X86_INS_OUT) - - @return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, - void *user_data, uint64_t begin, uint64_t end, ...) -{ - int ret = UC_ERR_OK; - int i = 0; - - struct hook *hook = calloc(1, sizeof(struct hook)); - if (hook == NULL) { - return UC_ERR_NOMEM; - } - - hook->begin = begin; - hook->end = end; - hook->type = type; - hook->callback = callback; - hook->user_data = user_data; - hook->refs = 0; - *hh = (uc_hook)hook; - - // UC_HOOK_INSN 有一个额外参数:指令ID - if (type & UC_HOOK_INSN) { - va_list valist; - - va_start(valist, end); - hook->insn = va_arg(valist, int); - va_end(valist); - - if (uc->insn_hook_validate) { - if (! uc->insn_hook_validate(hook->insn)) { - free(hook); - return UC_ERR_HOOK; - } - } - - if (uc->hook_insert) { - if (list_insert(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) { - free(hook); - return UC_ERR_NOMEM; - } - } else { - if (list_append(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) { - free(hook); - return UC_ERR_NOMEM; - } - } - - hook->refs++; - return UC_ERR_OK; - } - - while ((type >> i) > 0) { - if ((type >> i) & 1) { - if (i < UC_HOOK_MAX) { - if (uc->hook_insert) { - if (list_insert(&uc->hook[i], hook) == NULL) { - if (hook->refs == 0) { - free(hook); - } - return UC_ERR_NOMEM; - } - } else { - if (list_append(&uc->hook[i], hook) == NULL) { - if (hook->refs == 0) { - free(hook); - } - return UC_ERR_NOMEM; - } - } - hook->refs++; - } - } - i++; - } - - if (hook->refs == 0) { - free(hook); - } - - return ret; -} -``` - -使用示例: - -```cpp -#include -#include -#include "unicorn/unicorn.h" -using namespace std; - -int syscall_abi[] = { - UC_X86_REG_RAX, UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, - UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9 -}; - -uint64_t vals[7] = { 200, 10, 11, 12, 13, 14, 15 }; - -void* ptrs[7]; - -void uc_perror(const char* func, uc_err err) -{ - fprintf(stderr, "Error in %s(): %s\n", func, uc_strerror(err)); -} - -#define BASE 0x10000 - -// mov rax, 100; mov rdi, 1; mov rsi, 2; mov rdx, 3; mov r10, 4; mov r8, 5; mov r9, 6; syscall -#define CODE "\x48\xc7\xc0\x64\x00\x00\x00\x48\xc7\xc7\x01\x00\x00\x00\x48\xc7\xc6\x02\x00\x00\x00\x48\xc7\xc2\x03\x00\x00\x00\x49\xc7\xc2\x04\x00\x00\x00\x49\xc7\xc0\x05\x00\x00\x00\x49\xc7\xc1\x06\x00\x00\x00\x0f\x05" - -void hook_syscall(uc_engine* uc, void* user_data) -{ - int i; - - uc_reg_read_batch(uc, syscall_abi, ptrs, 7); - - printf("syscall: {"); - - for (i = 0; i < 7; i++) { - if (i != 0) printf(", "); - printf("%" PRIu64, vals[i]); - } - - printf("}\n"); -} - -void hook_code(uc_engine* uc, uint64_t addr, uint32_t size, void* user_data) -{ - printf("HOOK_CODE: 0x%" PRIx64 ", 0x%x\n", addr, size); -} - -int main() -{ - int i; - uc_hook sys_hook; - uc_err err; - uc_engine* uc; - - for (i = 0; i < 7; i++) { - ptrs[i] = &vals[i]; - } - - if ((err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc))) { - uc_perror("uc_open", err); - return 1; - } - - printf("reg_write_batch({200, 10, 11, 12, 13, 14, 15})\n"); - if ((err = uc_reg_write_batch(uc, syscall_abi, ptrs, 7))) { - uc_perror("uc_reg_write_batch", err); - return 1; - } - - memset(vals, 0, sizeof(vals)); - if ((err = uc_reg_read_batch(uc, syscall_abi, ptrs, 7))) { - uc_perror("uc_reg_read_batch", err); - return 1; - } - - printf("reg_read_batch = {"); - - for (i = 0; i < 7; i++) { - if (i != 0) printf(", "); - printf("%" PRIu64, vals[i]); - } - - printf("}\n"); - - // syscall - printf("\n"); - printf("running syscall shellcode\n"); - - if ((err = uc_hook_add(uc, &sys_hook, UC_HOOK_CODE, hook_syscall, NULL, 1, 0))) { - uc_perror("uc_hook_add", err); - return 1; - } - - if ((err = uc_mem_map(uc, BASE, 0x1000, UC_PROT_ALL))) { - uc_perror("uc_mem_map", err); - return 1; - } - - if ((err = uc_mem_write(uc, BASE, CODE, sizeof(CODE) - 1))) { - uc_perror("uc_mem_write", err); - return 1; - } - - if ((err = uc_emu_start(uc, BASE, BASE + sizeof(CODE) - 1, 0, 0))) { - uc_perror("uc_emu_start", err); - return 1; - } - - return 0; -} -``` - -输出 - -![image.png](API_Doc_Pic/aU1lbmxMjXA5g3K.png) - -对每条指令都进行hook - - - -### uc_hook_del - -``` -uc_err uc_hook_del(uc_engine *uc, uc_hook hh); -``` - -删除一个已注册的hook事件 - -``` -@uc: uc_open() 返回的句柄 -@hh: uc_hook_add() 返回的句柄 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_hook_del(uc_engine *uc, uc_hook hh) -{ - int i; - struct hook *hook = (struct hook *)hh; - - for (i = 0; i < UC_HOOK_MAX; i++) { - if (list_remove(&uc->hook[i], (void *)hook)) { - if (--hook->refs == 0) { - free(hook); - break; - } - } - } - return UC_ERR_OK; -} -``` - -使用示例: - -```cpp -if ((err = uc_hook_add(uc, &sys_hook, UC_HOOK_CODE, hook_syscall, NULL, 1, 0))) { - uc_perror("uc_hook_add", err); - return 1; -} - -if ((err = uc_hook_del(uc, &sys_hook))) { - uc_perror("uc_hook_del", err); - return 1; -} -``` - - - -### uc_mem_map - -```c -uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms); -``` - -为模拟映射一块内存。 - -``` -@uc: uc_open() 返回的句柄 -@address: 要映射到的新内存区域的起始地址。这个地址必须与4KB对齐,否则将返回UC_ERR_ARG错误。 -@size: 要映射到的新内存区域的大小。这个大小必须是4KB的倍数,否则将返回UC_ERR_ARG错误。 -@perms: 新映射区域的权限。参数必须是UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC或这些的组合,否则返回UC_ERR_ARG错误。 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms) -{ - uc_err res; - - if (uc->mem_redirect) { - address = uc->mem_redirect(address); - } - - res = mem_map_check(uc, address, size, perms); //内存安全检查 - if (res) - return res; - - return mem_map(uc, address, size, perms, uc->memory_map(uc, address, size, perms)); -} -``` - -使用示例同uc_hook_add。 - - - -### uc_mem_map_ptr - -```c -uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr); -``` - -在模拟中映射现有的主机内存。 - -``` -@uc: uc_open() 返回的句柄 -@address: 要映射到的新内存区域的起始地址。这个地址必须与4KB对齐,否则将返回UC_ERR_ARG错误。 -@size: 要映射到的新内存区域的大小。这个大小必须是4KB的倍数,否则将返回UC_ERR_ARG错误。 -@perms: 新映射区域的权限。参数必须是UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC或这些的组合,否则返回UC_ERR_ARG错误。 -@ptr: 指向支持新映射内存的主机内存的指针。映射的主机内存的大小应该与size的大小相同或更大,并且至少使用PROT_READ | PROT_WRITE进行映射,否则不定义映射。 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr) -{ - uc_err res; - - if (ptr == NULL) - return UC_ERR_ARG; - - if (uc->mem_redirect) { - address = uc->mem_redirect(address); - } - - res = mem_map_check(uc, address, size, perms); //内存安全检查 - if (res) - return res; - - return mem_map(uc, address, size, UC_PROT_ALL, uc->memory_map_ptr(uc, address, size, perms, ptr)); -} -``` - -使用示例同uc_mem_map - - - -### uc_mem_unmap - -```c -uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size); -``` - -取消对模拟内存区域的映射 - -``` -@uc: uc_open() 返回的句柄 -@address: 要映射到的新内存区域的起始地址。这个地址必须与4KB对齐,否则将返回UC_ERR_ARG错误。 -@size: 要映射到的新内存区域的大小。这个大小必须是4KB的倍数,否则将返回UC_ERR_ARG错误。 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) -{ - MemoryRegion *mr; - uint64_t addr; - size_t count, len; - - if (size == 0) - // 没有要取消映射的区域 - return UC_ERR_OK; - - // 地址必须对齐到 uc->target_page_size - if ((address & uc->target_page_align) != 0) - return UC_ERR_ARG; - - // 大小必须是 uc->target_page_size 的倍数 - if ((size & uc->target_page_align) != 0) - return UC_ERR_ARG; - - if (uc->mem_redirect) { - address = uc->mem_redirect(address); - } - - // 检查用户请求的整个块是否被映射 - if (!check_mem_area(uc, address, size)) - return UC_ERR_NOMEM; - - // 如果这个区域跨越了相邻的区域,可能需要分割区域 - addr = address; - count = 0; - while(count < size) { - mr = memory_mapping(uc, addr); - len = (size_t)MIN(size - count, mr->end - addr); - if (!split_region(uc, mr, addr, len, true)) - return UC_ERR_NOMEM; - - // 取消映射 - mr = memory_mapping(uc, addr); - if (mr != NULL) - uc->memory_unmap(uc, mr); - count += len; - addr += len; - } - - return UC_ERR_OK; -} -``` - -使用示例: - -```cpp -if ((err = uc_mem_map(uc, BASE, 0x1000, UC_PROT_ALL))) { - uc_perror("uc_mem_map", err); - return 1; -} - -if ((err = uc_mem_unmap(uc, BASE, 0x1000))) { - uc_perror("uc_mem_unmap", err); - return 1; -} -``` - - - -### uc_mem_protect - -```c -uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t perms); -``` - -设置模拟内存的权限 - -``` -@uc: uc_open() 返回的句柄 -@address: 要映射到的新内存区域的起始地址。这个地址必须与4KB对齐,否则将返回UC_ERR_ARG错误。 -@size: 要映射到的新内存区域的大小。这个大小必须是4KB的倍数,否则将返回UC_ERR_ARG错误。 -@perms: 映射区域的新权限。参数必须是UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC或这些的组合,否则返回UC_ERR_ARG错误。 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint32_t perms) -{ - MemoryRegion *mr; - uint64_t addr = address; - size_t count, len; - bool remove_exec = false; - - if (size == 0) - // trivial case, no change - return UC_ERR_OK; - - // address must be aligned to uc->target_page_size - if ((address & uc->target_page_align) != 0) - return UC_ERR_ARG; - - // size must be multiple of uc->target_page_size - if ((size & uc->target_page_align) != 0) - return UC_ERR_ARG; - - // check for only valid permissions - if ((perms & ~UC_PROT_ALL) != 0) - return UC_ERR_ARG; - - if (uc->mem_redirect) { - address = uc->mem_redirect(address); - } - - // check that user's entire requested block is mapped - if (!check_mem_area(uc, address, size)) - return UC_ERR_NOMEM; - - // Now we know entire region is mapped, so change permissions - // We may need to split regions if this area spans adjacent regions - addr = address; - count = 0; - while(count < size) { - mr = memory_mapping(uc, addr); - len = (size_t)MIN(size - count, mr->end - addr); - if (!split_region(uc, mr, addr, len, false)) - return UC_ERR_NOMEM; - - mr = memory_mapping(uc, addr); - // will this remove EXEC permission? - if (((mr->perms & UC_PROT_EXEC) != 0) && ((perms & UC_PROT_EXEC) == 0)) - remove_exec = true; - mr->perms = perms; - uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0); - - count += len; - addr += len; - } - - // if EXEC permission is removed, then quit TB and continue at the same place - if (remove_exec) { - uc->quit_request = true; - uc_emu_stop(uc); - } - - return UC_ERR_OK; -} -``` - -使用示例: - -```cpp -if ((err = uc_mem_protect(uc, BASE, 0x1000, UC_PROT_ALL))) { //可读可写可执行 - uc_perror("uc_mem_protect", err); - return 1; -} -``` - - - -### uc_mem_regions - -```c -uc_err uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count); -``` - -检索由 uc_mem_map() 和 uc_mem_map_ptr() 映射的内存的信息。 - -这个API为@regions分配内存,用户之后必须通过free()释放这些内存来避免内存泄漏。 - -``` -@uc: uc_open() 返回的句柄 -@regions: 指向 uc_mem_region 结构体的数组的指针. 由Unicorn申请,必须通过uc_free()释放这些内存 -@count: 指向@regions中包含的uc_mem_region结构体的数量的指针 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码分析 - -```c -uint32_t uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count) -{ - uint32_t i; - uc_mem_region *r = NULL; - - *count = uc->mapped_block_count; - - if (*count) { - r = g_malloc0(*count * sizeof(uc_mem_region)); - if (r == NULL) { - // 内存不足 - return UC_ERR_NOMEM; - } - } - - for (i = 0; i < *count; i++) { - r[i].begin = uc->mapped_blocks[i]->addr; - r[i].end = uc->mapped_blocks[i]->end - 1; - r[i].perms = uc->mapped_blocks[i]->perms; - } - - *regions = r; - - return UC_ERR_OK; -} -``` - -使用示例: - -```cpp -#include -#include -#include "unicorn/unicorn.h" -using namespace std; - -int main() -{ - uc_err err; - uc_engine* uc; - - if ((err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc))) { - uc_perror("uc_open", err); - return 1; - } - - if ((err = uc_mem_map(uc, BASE, 0x1000, UC_PROT_ALL))) { - uc_perror("uc_mem_map", err); - return 1; - } - - uc_mem_region *region; - uint32_t count; - - if ((err = uc_mem_regions(uc, ®ion, &count))) { - uc_perror("uc_mem_regions", err); - return 1; - } - - cout << "起始地址: 0x" << hex << region->begin << " 结束地址: 0x" << hex << region->end << " 内存权限: " <perms << " 已申请内存块数: " << count << endl; - - if ((err = uc_free(region))) { ////注意释放内存 - uc_perror("uc_free", err); - return 1; - } - - return 0; -} -``` - -输出 - -![image.png](API_Doc_Pic/kbrF7NdV6LDxnYI.png) - - - -### uc_free - -```c -uc_err uc_free(void *mem); -``` - -释放由 uc_context_alloc 和 uc_mem_regions 申请的内存 - -``` -@mem: 由uc_context_alloc (返回 *context), 或由 uc_mem_regions (返回 *regions)申请的内存 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_free(void *mem) -{ - g_free(mem); - return UC_ERR_OK; -} - -void g_free(gpointer ptr) -{ - free(ptr); -} -``` - -使用示例同uc_mem_regions - - - -### uc_context_alloc - -```c -uc_err uc_context_alloc(uc_engine *uc, uc_context **context); -``` - -分配一个可以与uc_context_{save,restore}一起使用的区域来执行CPU上下文的快速保存/回滚,包括寄存器和内部元数据。上下文不能在具有不同架构或模式的引擎实例之间共享。 - -``` -@uc: uc_open() 返回的句柄 -@context: 指向uc_engine*的指针。当这个函数成功返回时,将使用指向新上下文的指针更新它。之后必须使用uc_free()释放这些分配的内存。 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_context_alloc(uc_engine *uc, uc_context **context) -{ - struct uc_context **_context = context; - size_t size = uc->cpu_context_size; - - *_context = g_malloc(size); - if (*_context) { - (*_context)->jmp_env_size = sizeof(*uc->cpu->jmp_env); - (*_context)->context_size = size - sizeof(uc_context) - (*_context)->jmp_env_size; - return UC_ERR_OK; - } else { - return UC_ERR_NOMEM; - } -} -``` - -使用示例 - -```cpp -#include -#include -#include "unicorn/unicorn.h" -using namespace std; - -#define ADDRESS 0x1000 -#define X86_CODE32_INC "\x40" // INC eax - -int main() -{ - uc_engine* uc; - uc_context* context; - uc_err err; - - int r_eax = 0x1; // EAX 寄存器 - - printf("===================================\n"); - printf("Save/restore CPU context in opaque blob\n"); - - err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); - if (err) { - printf("Failed on uc_open() with error returned: %u\n", err); - return 0; - } - - uc_mem_map(uc, ADDRESS, 8 * 1024, UC_PROT_ALL); - - if (uc_mem_write(uc, ADDRESS, X86_CODE32_INC, sizeof(X86_CODE32_INC) - 1)) { - printf("Failed to write emulation code to memory, quit!\n"); - return 0; - } - - // 初始化寄存器 - uc_reg_write(uc, UC_X86_REG_EAX, &r_eax); - - printf(">>> Running emulation for the first time\n"); - - err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INC) - 1, 0, 0); - if (err) { - printf("Failed on uc_emu_start() with error returned %u: %s\n", - err, uc_strerror(err)); - } - - printf(">>> Emulation done. Below is the CPU context\n"); - - uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); - printf(">>> EAX = 0x%x\n", r_eax); - - // 申请并保存 CPU 上下文 - printf(">>> Saving CPU context\n"); - - err = uc_context_alloc(uc, &context); - if (err) { - printf("Failed on uc_context_alloc() with error returned: %u\n", err); - return 0; - } - - err = uc_context_save(uc, context); - if (err) { - printf("Failed on uc_context_save() with error returned: %u\n", err); - return 0; - } - - printf(">>> Running emulation for the second time\n"); - - err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INC) - 1, 0, 0); - if (err) { - printf("Failed on uc_emu_start() with error returned %u: %s\n", - err, uc_strerror(err)); - } - - printf(">>> Emulation done. Below is the CPU context\n"); - - uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); - printf(">>> EAX = 0x%x\n", r_eax); - - // 恢复 CPU 上下文 - err = uc_context_restore(uc, context); - if (err) { - printf("Failed on uc_context_restore() with error returned: %u\n", err); - return 0; - } - - printf(">>> CPU context restored. Below is the CPU context\n"); - - uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); - printf(">>> EAX = 0x%x\n", r_eax); - - // 释放 CPU 上下文 - err = uc_free(context); - if (err) { - printf("Failed on uc_free() with error returned: %u\n", err); - return 0; - } - - uc_close(uc); - - return 0; -} -``` - -输出 - -![image.png](API_Doc_Pic/juNPWvwGUlraKRh.png) - - - -### uc_context_save - -```c -uc_err uc_context_save(uc_engine *uc, uc_context *context); -``` - -保存当前CPU上下文 - -``` -@uc: uc_open() 返回的句柄 -@context: uc_context_alloc() 返回的句柄 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_context_save(uc_engine *uc, uc_context *context) -{ - struct uc_context *_context = context; - memcpy(_context->data, uc->cpu->env_ptr, _context->size); - return UC_ERR_OK; -} -``` - -使用示例同uc_context_alloc() - - - -### uc_context_restore - -```c -uc_err uc_context_restore(uc_engine *uc, uc_context *context); -``` - -恢复已保存的CPU上下文 - -``` -@uc: uc_open() 返回的句柄 -@context: uc_context_alloc() 返回并且已使用 uc_context_save 保存的句柄 - -@return 成功则返回UC_ERR_OK , 否则返回 uc_err 枚举的其他错误类型 -``` - -源码实现 - -```c -uc_err uc_context_restore(uc_engine *uc, uc_context *context) -{ - struct uc_context *_context = context; - memcpy(uc->cpu->env_ptr, _context->data, _context->size); - return UC_ERR_OK; -} -``` - -使用示例同uc_context_alloc() - - - -### uc_context_size - -```c -size_t uc_context_size(uc_engine *uc); -``` - -返回存储cpu上下文所需的大小。可以用来分配一个缓冲区来包含cpu上下文,并直接调用uc_context_save。 - -``` -@uc: uc_open() 返回的句柄 - -@return 存储cpu上下文所需的大小,类型为 size_t. -``` - -源码实现 - -```c -size_t uc_context_size(uc_engine *uc) -{ - return sizeof(uc_context) + uc->cpu_context_size + sizeof(*uc->cpu->jmp_env); -} -``` - -使用示例同uc_context_alloc() - - - diff --git a/docs/README.md b/docs/README.md index f80f57da..47bd29f5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,6 +12,6 @@ Documention of Unicorn engine. http://unicorn-engine.org/docs/beyond_qemu.html -* Micro Uncorn-Engine API Documentation in Chinese +* Uncorn-Engine Documentation - https://github.com/kabeor/Micro-Unicorn-Engine-API-Documentation + https://github.com/kabeor/Unicorn-Engine-Documentation diff --git a/docs/Unicorn_Engine_Documentation b/docs/Unicorn_Engine_Documentation new file mode 160000 index 00000000..e1111e1b --- /dev/null +++ b/docs/Unicorn_Engine_Documentation @@ -0,0 +1 @@ +Subproject commit e1111e1b8b253bf7292ad911f43c125808a95f1e diff --git a/qemu/target/ppc/cpu.h b/qemu/target/ppc/cpu.h index 0357a4ca..26ed1680 100644 --- a/qemu/target/ppc/cpu.h +++ b/qemu/target/ppc/cpu.h @@ -2018,9 +2018,13 @@ enum { PPC_MEM_TLBIA = 0x0000000010000000ULL, PPC_MEM_TLBIE = 0x0000000020000000ULL, PPC_MEM_TLBSYNC = 0x0000000040000000ULL, + +// The enum in msvc is 32bit **signed**. +// https://godbolt.org/z/nYbvWPWET +#ifndef _MSC_VER /* sync instruction */ PPC_MEM_SYNC = 0x0000000080000000ULL, -#ifndef _MSC_VER + /* eieio instruction */ PPC_MEM_EIEIO = 0x0000000100000000ULL, @@ -2084,6 +2088,7 @@ enum { /* popcntw and popcntd instructions */ PPC_POPCNTWD = 0x8000000000000000ULL, #else +#define PPC_MEM_SYNC 0x0000000080000000ULL #define PPC_MEM_EIEIO 0x0000000100000000ULL #define PPC_CACHE 0x0000000200000000ULL #define PPC_CACHE_ICBI 0x0000000400000000ULL diff --git a/tests/unit/test_ppc.c b/tests/unit/test_ppc.c index 972d24c6..c457bd70 100644 --- a/tests/unit/test_ppc.c +++ b/tests/unit/test_ppc.c @@ -3,6 +3,34 @@ const uint64_t code_start = 0x1000; const uint64_t code_len = 0x4000; +static void uc_common_setup(uc_engine** uc, uc_arch arch, uc_mode mode, const char* code, uint64_t size) { + OK(uc_open(arch, mode, uc)); + OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL)); + OK(uc_mem_write(*uc, code_start, code, size)); +} + +static void test_ppc32_add() { + uc_engine* uc; + char code[] = "\x7f\x46\x1a\x14"; // ADD 26, 6, 3 + int reg; + + uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_32 | UC_MODE_BIG_ENDIAN, code, sizeof(code) - 1); + + reg = 42; + OK(uc_reg_write(uc, UC_PPC_REG_3, ®)); + reg = 1337; + OK(uc_reg_write(uc, UC_PPC_REG_6, ®)); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_reg_read(uc, UC_PPC_REG_26, ®)); + + TEST_CHECK(reg == 1379); + + OK(uc_close(uc)); +} + TEST_LIST = { - { NULL, NULL } + { "test_ppc32_add", test_ppc32_add }, + { NULL, NULL} }; \ No newline at end of file