Python binding setup refactoring + cibuildwheel workflow (#2026)
* Python bindings: Make the test scripts handy for pytest * Python bindings: Update MANIFEST.in with new paths * Update .gitignore to exclude PyCharm-related files/folders * Python bindings: Update CMakeLists.txt in order to set CMAKE_OSX_ARCHITECTURES var * Python bindings: - Moved project package settings to the new TOML format - Refactored setup.py to cleanup/improve the code and make it ready for cibuildwheel - Updated README.md with the package long description part - Removed setup.cfg since universal wheel building will be deprecated soon * Python bindings: - Replaced old PyPI-publishing.yml workflow with brand-new one based on cibuildwheel - Removed old building scripts * Replaced macos-12 runner with macos-13 since it will be removed soon * Python bindings: Specify SYSTEM_VERSION_COMPAT=0 env var for macos-13 x86_64 runner as per cibuildwheel warning message * Python bindings: Enable i686 for debugging * Python bindings: Enable DEBUG flag according to the presence of tag release * Python bindings: Added matrix to cover i686 manylinux/musllinux builds * Python bindings: - Replaced macos-14 runner with macos-latest - Bumped cibuildwheel GitHub action to 2.21.3 version * Python bindings: - Adapt test_uc_ctl_tb_cache test to the recent changes - Fixed typos - PEP8 fixes * GitHub Action Workflow: Introduce BUILD_TYPE env var to select build type according to the presence of tag release --------- Co-authored-by: mio <mio@lazym.io>
This commit is contained in:
parent
c42cc0fe86
commit
6fbbf3089a
167
.github/workflows/PyPI-publishing.yml
vendored
167
.github/workflows/PyPI-publishing.yml
vendored
@ -1,167 +0,0 @@
|
||||
name: PyPI 📦 Distribution
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- ".gitignore"
|
||||
- "docs/**"
|
||||
- "README"
|
||||
- "CREDITS.TXT"
|
||||
- "COPYING_GLIB"
|
||||
- "COPYING.LGPL2"
|
||||
- "AUTHORS.TXT"
|
||||
- "CHANGELOG"
|
||||
- "COPYING"
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
name: ${{ matrix.config.name }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- {
|
||||
os: windows-2019,
|
||||
arch: x64,
|
||||
python-ver: '3.8',
|
||||
name: 'win_amd64'
|
||||
}
|
||||
- {
|
||||
os: windows-2019,
|
||||
arch: x32,
|
||||
python-ver: '3.8',
|
||||
name: 'win32'
|
||||
}
|
||||
- {
|
||||
os: ubuntu-latest,
|
||||
arch: x64,
|
||||
python-ver: '3.8',
|
||||
name: 'musllinux'
|
||||
}
|
||||
- {
|
||||
os: ubuntu-latest,
|
||||
arch: x64,
|
||||
python-ver: '3.8',
|
||||
name: 'manylinux2014_x86_64'
|
||||
}
|
||||
- {
|
||||
os: ubuntu-latest,
|
||||
arch: x32,
|
||||
python-ver: '3.8',
|
||||
name: 'manylinux2014_i686'
|
||||
}
|
||||
- {
|
||||
os: ubuntu-latest,
|
||||
arch: aarch64,
|
||||
python-ver: '3.8',
|
||||
name: 'manylinux2014_aarch64'
|
||||
}
|
||||
- {
|
||||
os: ubuntu-latest,
|
||||
arch: x64,
|
||||
python-ver: '3.8',
|
||||
name: 'sdist'
|
||||
}
|
||||
- {
|
||||
os: macos-12,
|
||||
arch: x86_64,
|
||||
python-ver: '3.8',
|
||||
name: 'macos_x86_64'
|
||||
}
|
||||
- {
|
||||
os: macos-14,
|
||||
arch: arm64,
|
||||
python-ver: '3.10',
|
||||
name: 'macos_arm64'
|
||||
}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: '🛠️ Set up Python'
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.config.python-ver }}
|
||||
|
||||
- name: '🛠️ Add msbuild to PATH'
|
||||
if: contains(matrix.config.name, 'win')
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
with:
|
||||
vs-version: '16.5'
|
||||
|
||||
- name: '🛠️ Win MSVC 32 dev cmd setup'
|
||||
if: contains(matrix.config.name, 'win32')
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: x86
|
||||
|
||||
- name: '🛠️ Win MSVC 64 dev cmd setup'
|
||||
if: contains(matrix.config.name, 'win_amd64')
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: x64
|
||||
|
||||
- name: '🛠️ Win build dependencies'
|
||||
if: contains(matrix.config.name, 'win')
|
||||
shell: bash
|
||||
run: |
|
||||
choco install ninja cmake
|
||||
|
||||
- name: '🛠️ macOS dependencies'
|
||||
if: contains(matrix.config.name, 'macos')
|
||||
run: |
|
||||
brew install ninja
|
||||
|
||||
- name: '🛠️ pip dependencies'
|
||||
run: |
|
||||
pip install --upgrade setuptools wheel
|
||||
|
||||
- name: '🚧 Build distribution'
|
||||
shell: bash
|
||||
run: |
|
||||
if [ ${{ matrix.config.name }} == 'win32' ]; then
|
||||
cd bindings/python && python setup.py build -p win32 sdist bdist_wheel -p win32
|
||||
rm dist/*.tar.gz
|
||||
elif [ ${{ matrix.config.name }} == 'manylinux2014_i686' ]; then
|
||||
docker run --rm -v `pwd`/:/work dockcross/manylinux2014-x86 > ./dockcross
|
||||
chmod +x ./dockcross
|
||||
./dockcross bindings/python/build_wheel.sh
|
||||
elif [ ${{ matrix.config.name }} == 'manylinux2014_aarch64' ]; then
|
||||
docker run --rm -v `pwd`/:/work dockcross/manylinux2014-aarch64 > ./dockcross
|
||||
chmod +x ./dockcross
|
||||
./dockcross bindings/python/build_wheel.sh --plat-name manylinux2014_aarch64
|
||||
elif [ ${{ matrix.config.name }} == 'manylinux2014_x86_64' ]; then
|
||||
docker run --rm -v `pwd`/:/work dockcross/manylinux2014-x64 > ./dockcross
|
||||
chmod +x ./dockcross
|
||||
./dockcross bindings/python/build_wheel.sh
|
||||
elif [ ${{ matrix.config.name }} == 'musllinux' ]; then
|
||||
docker run --rm -v `pwd`:/work -w /work python:3.7-alpine sh /work/bindings/python/musl_wheel.sh
|
||||
elif [ ${{ matrix.config.name }} == 'sdist' ]; then
|
||||
cd bindings/python && python setup.py sdist
|
||||
elif [ ${{ matrix.config.name }} == 'macos_arm64' ]; then
|
||||
cd bindings/python && _PYTHON_HOST_PLATFORM="macosx-11.0-arm64" ARCHFLAGS="-arch arm64" python setup.py bdist_wheel
|
||||
else
|
||||
cd bindings/python && python setup.py bdist_wheel
|
||||
fi
|
||||
- name: '📤 Upload artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.config.name }}
|
||||
path: ${{ github.workspace }}/bindings/python/dist/*
|
||||
|
||||
publish:
|
||||
needs: [build]
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref, 'refs/tags')
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
merge-multiple: true
|
||||
path: dist
|
||||
|
||||
- name: '📦 Publish distribution to PyPI'
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.pypi_pass }}
|
998
.github/workflows/build-uc2.yml
vendored
998
.github/workflows/build-uc2.yml
vendored
File diff suppressed because it is too large
Load Diff
360
.github/workflows/build-wheels-publish.yml
vendored
Normal file
360
.github/workflows/build-wheels-publish.yml
vendored
Normal file
@ -0,0 +1,360 @@
|
||||
name: Build wheels with cibuildwheel
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- ".gitignore"
|
||||
- "AUTHORS.TXT"
|
||||
- "COPYING"
|
||||
- "COPYING.LGPL2"
|
||||
- "COPYING_GLIB"
|
||||
- "CREDITS.TXT"
|
||||
- "ChangeLog"
|
||||
- "README.md"
|
||||
- "docs/**"
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
# Enable DEBUG flag if not tag release
|
||||
UNICORN_DEBUG: ${{ startsWith(github.ref, 'refs/tags') && '0' || '1' }}
|
||||
|
||||
jobs:
|
||||
# job to be executed for every push - testing purpose
|
||||
build_wheels_python38_only:
|
||||
name: Building on ${{ matrix.os }} - ${{ matrix.arch }} ${{ matrix.cibw_build }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# NOTE: aarch64 builds are super slow due to QEMU emulation. Making this to parallelize and speed up workflow
|
||||
# i686 - manylinux
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp38-manylinux' }
|
||||
# i686 - musllinux
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp38-musllinux' }
|
||||
# x86_64 - manylinux
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp38-manylinux' }
|
||||
# x86_64 - musllinux
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp38-musllinux' }
|
||||
# aarch64 - manylinux
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp38-manylinux' }
|
||||
# aarch64 - musllinux
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp38-musllinux' }
|
||||
- { os: macos-13, arch: x86_64, cibw_build: '' }
|
||||
- { os: macos-latest, arch: arm64, cibw_build: '' }
|
||||
- { os: windows-2019, arch: AMD64, cibw_build: '' }
|
||||
- { os: windows-2019, arch: x86, cibw_build: '' }
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: '🛠️ Add msbuild to PATH'
|
||||
if: runner.os == 'Windows'
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
with:
|
||||
vs-version: '16.5'
|
||||
|
||||
- name: '🛠️ Win build dependencies'
|
||||
if: runner.os == 'Windows'
|
||||
shell: bash
|
||||
run: |
|
||||
choco install ninja cmake
|
||||
|
||||
- name: '🛠️ macOS dependencies'
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew install ninja
|
||||
|
||||
# https://cibuildwheel.pypa.io/en/stable/faq/#macos-building-cpython-38-wheels-on-arm64
|
||||
- uses: actions/setup-python@v5
|
||||
if: runner.os == 'macOS' && runner.arch == 'ARM64'
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
- name: '🛠️ Win MSVC 32 dev cmd setup'
|
||||
if: runner.os == 'Windows' && matrix.arch == 'x86'
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: x86
|
||||
|
||||
- name: '🛠️ Win MSVC 64 dev cmd setup'
|
||||
if: runner.os == 'Windows' && matrix.arch == 'AMD64'
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: x64
|
||||
|
||||
- name: '🛠️ Set up QEMU'
|
||||
if: runner.os == 'Linux'
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: '🚧 cibuildwheel run - Linux'
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
uses: pypa/cibuildwheel@v2.21.3
|
||||
env:
|
||||
CIBW_BUILD_FRONTEND: build
|
||||
CIBW_BUILD: ${{ matrix.cibw_build }}*
|
||||
CIBW_ARCHS: ${{ matrix.arch }}
|
||||
CIBW_ENVIRONMENT: DEBUG=${{ env.UNICORN_DEBUG }}
|
||||
CIBW_ENVIRONMENT_PASS_LINUX: DEBUG
|
||||
CIBW_TEST_REQUIRES: pytest
|
||||
CIBW_TEST_COMMAND: pytest {package}/tests
|
||||
with:
|
||||
package-dir: bindings/python
|
||||
output-dir: wheelhouse
|
||||
|
||||
- name: '🚧 cibuildwheel run - Windows'
|
||||
if: matrix.os == 'windows-2019'
|
||||
uses: pypa/cibuildwheel@v2.21.3
|
||||
env:
|
||||
CIBW_BUILD_FRONTEND: build
|
||||
CIBW_BUILD: 'cp38*'
|
||||
CIBW_ARCHS: ${{ matrix.arch }}
|
||||
CIBW_ENVIRONMENT: DEBUG=${{ env.UNICORN_DEBUG }}
|
||||
CIBW_TEST_REQUIRES: pytest
|
||||
CIBW_TEST_COMMAND: pytest {package}/tests
|
||||
with:
|
||||
package-dir: bindings/python
|
||||
output-dir: wheelhouse
|
||||
|
||||
- name: '🚧 cibuildwheel run - MacOS x86_84'
|
||||
if: matrix.os == 'macos-13'
|
||||
uses: pypa/cibuildwheel@v2.21.3
|
||||
env:
|
||||
CIBW_BUILD_FRONTEND: build
|
||||
CIBW_BUILD: 'cp38*'
|
||||
CIBW_ENVIRONMENT: SYSTEM_VERSION_COMPAT=0 DEBUG=${{ env.UNICORN_DEBUG }}
|
||||
CIBW_TEST_REQUIRES: pytest
|
||||
CIBW_TEST_COMMAND: pytest {package}/tests
|
||||
with:
|
||||
package-dir: bindings/python
|
||||
output-dir: wheelhouse
|
||||
|
||||
- name: '🚧 cibuildwheel run - MacOS arm64'
|
||||
if: matrix.os == 'macos-latest'
|
||||
uses: pypa/cibuildwheel@v2.21.3
|
||||
env:
|
||||
CIBW_BUILD_FRONTEND: build
|
||||
CIBW_BUILD: 'cp38*'
|
||||
CIBW_ENVIRONMENT: DEBUG=${{ env.UNICORN_DEBUG }}
|
||||
CIBW_TEST_REQUIRES: pytest
|
||||
CIBW_TEST_COMMAND: pytest {package}/tests
|
||||
# https://github.com/pypa/cibuildwheel/pull/1169
|
||||
CIBW_TEST_SKIP: "cp38-macosx_*:arm64"
|
||||
with:
|
||||
package-dir: bindings/python
|
||||
output-dir: wheelhouse
|
||||
|
||||
# we re-tag cp38 wheel (just an old one) with py2 tag. Hacky but it works...
|
||||
- name: '🚧 Python 2.7 wheels re-tagging - Windows'
|
||||
if: matrix.os == 'windows-2019'
|
||||
run: |
|
||||
python -m pip install -U pip wheel && Get-ChildItem -Path wheelhouse/ -Filter *cp38*.whl | Foreach-Object {
|
||||
python -m wheel tags --python-tag='py2' --abi-tag=none $_.FullName
|
||||
}
|
||||
- name: '🚧 Python 2.7 wheels re-tagging - Non-Windows'
|
||||
if: matrix.os != 'windows-2019'
|
||||
env:
|
||||
PIP_BREAK_SYSTEM_PACKAGES: 1
|
||||
run: |
|
||||
python3 -m pip install -U pip wheel && python3 -m wheel tags --python-tag='py2' --abi-tag=none wheelhouse/*cp38*.whl
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
|
||||
path: ./wheelhouse/*.whl
|
||||
|
||||
# Job to be executed to build all wheels for all platforms/architectures/python versions only for tag release
|
||||
build_wheels_all_versions:
|
||||
name: Building on ${{ matrix.os }} - ${{ matrix.arch }} ${{ matrix.cibw_build }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# NOTE: aarch64 builds are super slow due to QEMU emulation. Making this to parallelize and speed up workflow
|
||||
# i686 - manylinux
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp37-manylinux' }
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp39-manylinux' }
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp310-manylinux' }
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp311-manylinux' }
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp312-manylinux' }
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp313-manylinux' }
|
||||
# i686 - musllinux
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp37-musllinux' }
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp39-musllinux' }
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp310-musllinux' }
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp311-musllinux' }
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp312-musllinux' }
|
||||
- { os: ubuntu-latest, arch: i686, cibw_build: 'cp313-musllinux' }
|
||||
# x86_64 - manylinux
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp37-manylinux' }
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp39-manylinux' }
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp310-manylinux' }
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp311-manylinux' }
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp312-manylinux' }
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp313-manylinux' }
|
||||
# x86_64 - musllinux
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp37-musllinux' }
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp39-musllinux' }
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp310-musllinux' }
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp311-musllinux' }
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp312-musllinux' }
|
||||
- { os: ubuntu-latest, arch: x86_64, cibw_build: 'cp313-musllinux' }
|
||||
# aarch64 - manylinux
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp37-manylinux' }
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp39-manylinux' }
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp310-manylinux' }
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp311-manylinux' }
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp312-manylinux' }
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp313-manylinux' }
|
||||
# aarch64 - musllinux
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp37-musllinux' }
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp39-musllinux' }
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp310-musllinux' }
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp311-musllinux' }
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp312-musllinux' }
|
||||
- { os: ubuntu-latest, arch: aarch64, cibw_build: 'cp313-musllinux' }
|
||||
- { os: macos-13, arch: x86_64, cibw_build: '' }
|
||||
- { os: macos-latest, arch: arm64, cibw_build: '' }
|
||||
- { os: windows-2019, arch: AMD64, cibw_build: '' }
|
||||
- { os: windows-2019, arch: x86, cibw_build: '' }
|
||||
if: startsWith(github.ref, 'refs/tags')
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: '🛠️ Add msbuild to PATH'
|
||||
if: runner.os == 'Windows'
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
with:
|
||||
vs-version: '16.5'
|
||||
|
||||
- name: '🛠️ Win build dependencies'
|
||||
if: runner.os == 'Windows'
|
||||
shell: bash
|
||||
run: |
|
||||
choco install ninja cmake
|
||||
|
||||
- name: '🛠️ macOS dependencies'
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew install ninja
|
||||
|
||||
- name: '🛠️ Win MSVC 32 dev cmd setup'
|
||||
if: runner.os == 'Windows' && matrix.arch == 'x86'
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: x86
|
||||
|
||||
- name: '🛠️ Win MSVC 64 dev cmd setup'
|
||||
if: runner.os == 'Windows' && matrix.arch == 'AMD64'
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: x64
|
||||
|
||||
- name: '🛠️ Set up QEMU'
|
||||
if: runner.os == 'Linux'
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: '🚧 cibuildwheel run - Linux'
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
uses: pypa/cibuildwheel@v2.21.3
|
||||
env:
|
||||
CIBW_BUILD_FRONTEND: build
|
||||
CIBW_BUILD: ${{ matrix.cibw_build }}*
|
||||
CIBW_ARCHS: ${{ matrix.arch }}
|
||||
CIBW_ENVIRONMENT: DEBUG=${{ env.UNICORN_DEBUG }}
|
||||
CIBW_ENVIRONMENT_PASS_LINUX: DEBUG
|
||||
CIBW_TEST_REQUIRES: pytest
|
||||
CIBW_TEST_COMMAND: pytest {package}/tests
|
||||
with:
|
||||
package-dir: bindings/python
|
||||
output-dir: wheelhouse
|
||||
|
||||
- name: '🚧 cibuildwheel run - Windows'
|
||||
if: matrix.os == 'windows-2019'
|
||||
uses: pypa/cibuildwheel@v2.21.3
|
||||
env:
|
||||
CIBW_BUILD_FRONTEND: build
|
||||
CIBW_SKIP: '*36* *38*'
|
||||
CIBW_BUILD: 'cp*'
|
||||
CIBW_ENVIRONMENT: DEBUG=${{ env.UNICORN_DEBUG }}
|
||||
CIBW_ARCHS: ${{ matrix.arch }}
|
||||
CIBW_TEST_REQUIRES: pytest
|
||||
CIBW_TEST_COMMAND: pytest {package}/tests
|
||||
with:
|
||||
package-dir: bindings/python
|
||||
output-dir: wheelhouse
|
||||
|
||||
- name: '🚧 cibuildwheel run - MacOS x86_84'
|
||||
if: matrix.os == 'macos-13'
|
||||
uses: pypa/cibuildwheel@v2.21.3
|
||||
env:
|
||||
CIBW_BUILD_FRONTEND: build
|
||||
CIBW_SKIP: '*36* *38*'
|
||||
CIBW_BUILD: 'cp*'
|
||||
CIBW_ENVIRONMENT: DEBUG=${{ env.UNICORN_DEBUG }}
|
||||
CIBW_TEST_REQUIRES: pytest
|
||||
CIBW_TEST_COMMAND: pytest {package}/tests
|
||||
with:
|
||||
package-dir: bindings/python
|
||||
output-dir: wheelhouse
|
||||
|
||||
- name: '🚧 cibuildwheel run - MacOS arm64'
|
||||
if: matrix.os == 'macos-latest'
|
||||
uses: pypa/cibuildwheel@v2.21.3
|
||||
env:
|
||||
CIBW_BUILD_FRONTEND: build
|
||||
CIBW_SKIP: '*36* *37* *38*'
|
||||
CIBW_BUILD: 'cp*'
|
||||
CIBW_ENVIRONMENT: DEBUG=${{ env.UNICORN_DEBUG }}
|
||||
CIBW_TEST_REQUIRES: pytest
|
||||
CIBW_TEST_COMMAND: pytest {package}/tests
|
||||
with:
|
||||
package-dir: bindings/python
|
||||
output-dir: wheelhouse
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
|
||||
path: ./wheelhouse/*.whl
|
||||
|
||||
make_sdist:
|
||||
name: Make SDist
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Optional, use if you use setuptools_scm
|
||||
submodules: true # Optional, use if you have submodules
|
||||
|
||||
- name: Build SDist
|
||||
run: |
|
||||
cd bindings/python
|
||||
python3 -m pip install -U pip build
|
||||
python3 -m build --sdist
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: bindings/python/dist/*.tar.gz
|
||||
|
||||
publish:
|
||||
needs: [ build_wheels_python38_only, build_wheels_all_versions, make_sdist ]
|
||||
environment: pypi
|
||||
permissions:
|
||||
id-token: write
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref, 'refs/tags')
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
merge-multiple: true
|
||||
path: dist
|
||||
|
||||
- name: Show downloaded artifacts
|
||||
run: ls -laR dist
|
||||
|
||||
- name: '📦 Publish distribution to PyPI'
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.pypi_pass }}
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -90,4 +90,10 @@ packages/
|
||||
cmocka/
|
||||
zig-cache/
|
||||
zig-out/
|
||||
.cache
|
||||
.cache
|
||||
|
||||
##################
|
||||
## PyCharm Project
|
||||
##################
|
||||
|
||||
.idea/
|
||||
|
@ -30,6 +30,24 @@ if(APPLE AND NOT CMAKE_C_COMPILER)
|
||||
set(CMAKE_C_COMPILER "/usr/bin/cc")
|
||||
endif()
|
||||
|
||||
# Source: https://github.com/capstone-engine/capstone/blob/next/CMakeLists.txt
|
||||
# If building for OSX it's best to allow CMake to handle building both architectures
|
||||
if(APPLE)
|
||||
# The cibuildwheel on Github Actions sets this env variable
|
||||
# with the architecture flags it wants to build for.
|
||||
if(DEFINED ENV{ARCHFLAGS})
|
||||
if("$ENV{ARCHFLAGS}" STREQUAL "-arch arm64 -arch x86_64")
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64")
|
||||
elseif("$ENV{ARCHFLAGS}" STREQUAL "-arch arm64")
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64")
|
||||
elseif("$ENV{ARCHFLAGS}" STREQUAL "-arch x86_64")
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64")
|
||||
endif()
|
||||
else()
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Detect if unicorn is compiled as the top-level project
|
||||
set(PROJECT_IS_TOP_LEVEL OFF)
|
||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
|
@ -1,4 +1,9 @@
|
||||
recursive-include src *
|
||||
recursive-include prebuilt *
|
||||
include LICENSE.TXT
|
||||
include README.TXT
|
||||
graft unicorn/lib
|
||||
graft unicorn/include
|
||||
global-include *.a
|
||||
global-include *.so.2
|
||||
global-include *.*lib
|
||||
global-include *.dll
|
||||
global-include *.h
|
||||
|
@ -1,3 +1,21 @@
|
||||
# Unicorn
|
||||
|
||||
Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framework
|
||||
based on [QEMU](http://qemu.org).
|
||||
|
||||
Unicorn offers some unparalleled features:
|
||||
|
||||
- Multi-architecture: ARM, ARM64 (ARMv8), M68K, MIPS, PowerPC, RISCV, SPARC, S390X, TriCore and X86 (16, 32, 64-bit)
|
||||
- Clean/simple/lightweight/intuitive architecture-neutral API
|
||||
- Implemented in pure C language, with bindings for Crystal, Clojure, Visual Basic, Perl, Rust, Ruby, Python, Java, .NET, Go, Delphi/Free Pascal, Haskell, Pharo, and Lua.
|
||||
- Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed)
|
||||
- High performance via Just-In-Time compilation
|
||||
- Support for fine-grained instrumentation at various levels
|
||||
- Thread-safety by design
|
||||
- Distributed under free software license GPLv2
|
||||
|
||||
Further information is available at http://www.unicorn-engine.org
|
||||
|
||||
# Python Bindings for Unicorn
|
||||
|
||||
Originally written by Nguyen Anh Quynh, polished and redesigned by elicn, maintained by all community contributors.
|
||||
|
@ -1,15 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e -x
|
||||
|
||||
cd bindings/python
|
||||
|
||||
# Compile wheels
|
||||
python3.7 setup.py bdist_wheel $@
|
||||
cd dist
|
||||
|
||||
# We can't repair an aarch64 wheel on x64 hosts
|
||||
# https://github.com/pypa/auditwheel/issues/244
|
||||
if [[ ! "$*" =~ "aarch64" ]];then
|
||||
auditwheel repair *.whl
|
||||
mv -f wheelhouse/*.whl .
|
||||
fi
|
@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# TODO: use cibuildwheel
|
||||
apk update
|
||||
apk add gcc make cmake pkgconfig linux-headers git musl-dev patchelf
|
||||
|
||||
python3 -m pip install -U pip setuptools auditwheel
|
||||
|
||||
cd bindings/python && python3 setup.py bdist_wheel && auditwheel repair dist/*.whl && mv -f wheelhouse/*.whl ./dist/
|
40
bindings/python/pyproject.toml
Normal file
40
bindings/python/pyproject.toml
Normal file
@ -0,0 +1,40 @@
|
||||
[build-system]
|
||||
requires = ["setuptools", "build", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "unicorn"
|
||||
version = "2.1.1"
|
||||
requires-python = ">= 2.7, != 3.0.*, != 3.1.*, != 3.2.*, != 3.3.*, != 3.4.*, != 3.5.*, != 3.6.*"
|
||||
authors = [
|
||||
{ name = "Nguyen Anh Quynh", email = "quynh@gmail.com" },
|
||||
]
|
||||
description = "Unicorn CPU emulator engine"
|
||||
readme = "README.md"
|
||||
keywords = ["emulation", "qemu", "unicorn"]
|
||||
classifiers = [
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: 3.10',
|
||||
'Programming Language :: Python :: 3.11',
|
||||
'Programming Language :: Python :: 3.12',
|
||||
'Programming Language :: Python :: 3.13',
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "http://www.unicorn-engine.org"
|
||||
Repository = "https://github.com/unicorn-engine/unicorn"
|
||||
"Bug Tracker" = "https://github.com/unicorn-engine/unicorn/issues"
|
||||
Changelog = "https://github.com/unicorn-engine/unicorn/blob/master/ChangeLog"
|
||||
|
||||
[project.optional-dependencies]
|
||||
test = [
|
||||
"pytest",
|
||||
"pytest-cov",
|
||||
]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
include = ["unicorn*"]
|
@ -1,31 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
python3 ./sample_arm.py
|
||||
echo "=========================="
|
||||
python3 ./sample_armeb.py
|
||||
echo "=========================="
|
||||
python3 ./sample_arm64.py
|
||||
echo "=========================="
|
||||
python3 ./sample_arm64eb.py
|
||||
echo "=========================="
|
||||
python3 ./sample_m68k.py
|
||||
echo "=========================="
|
||||
python3 ./sample_mips.py
|
||||
echo "=========================="
|
||||
python3 ./sample_ppc.py
|
||||
echo "=========================="
|
||||
python3 ./sample_riscv.py
|
||||
echo "=========================="
|
||||
python3 ./sample_s390x.py
|
||||
echo "=========================="
|
||||
python3 ./sample_sparc.py
|
||||
echo "=========================="
|
||||
python3 ./sample_tricore.py
|
||||
echo "=========================="
|
||||
python3 ./sample_x86.py
|
||||
echo "=========================="
|
||||
python3 ./shellcode.py
|
||||
echo "=========================="
|
||||
python3 ./sample_ctl.py
|
||||
echo "=========================="
|
||||
python3 ./sample_network_auditing.py
|
@ -1,2 +0,0 @@
|
||||
[bdist_wheel]
|
||||
universal=1
|
@ -1,29 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
# Python binding for Unicorn engine. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import shutil
|
||||
import sys
|
||||
import platform
|
||||
import setuptools
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from setuptools import setup
|
||||
from sysconfig import get_platform
|
||||
from setuptools.command.build import build
|
||||
from setuptools.command.sdist import sdist
|
||||
from setuptools.command.bdist_egg import bdist_egg
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
SYSTEM = sys.platform
|
||||
|
||||
# sys.maxint is 2**31 - 1 on both 32 and 64 bit mingw
|
||||
IS_64BITS = platform.architecture()[0] == '64bit'
|
||||
|
||||
# are we building from the repository or from a source distribution?
|
||||
ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
LIBS_DIR = os.path.join(ROOT_DIR, 'unicorn', 'lib')
|
||||
@ -32,29 +22,28 @@ SRC_DIR = os.path.join(ROOT_DIR, 'src')
|
||||
UC_DIR = SRC_DIR if os.path.exists(SRC_DIR) else os.path.join(ROOT_DIR, '../..')
|
||||
BUILD_DIR = os.path.join(UC_DIR, 'build_python')
|
||||
|
||||
VERSION = "2.1.1"
|
||||
|
||||
if SYSTEM == 'darwin':
|
||||
if sys.platform == 'darwin':
|
||||
LIBRARY_FILE = "libunicorn.2.dylib"
|
||||
STATIC_LIBRARY_FILE = "libunicorn.a"
|
||||
elif SYSTEM in ('win32', 'cygwin'):
|
||||
elif sys.platform in ('win32', 'cygwin'):
|
||||
LIBRARY_FILE = "unicorn.dll"
|
||||
STATIC_LIBRARY_FILE = "unicorn.lib"
|
||||
else:
|
||||
LIBRARY_FILE = "libunicorn.so.2"
|
||||
STATIC_LIBRARY_FILE = "libunicorn.a"
|
||||
|
||||
|
||||
def clean_bins():
|
||||
shutil.rmtree(LIBS_DIR, ignore_errors=True)
|
||||
shutil.rmtree(HEADERS_DIR, ignore_errors=True)
|
||||
|
||||
|
||||
def copy_sources():
|
||||
"""Copy the C sources into the source directory.
|
||||
"""
|
||||
Copy the C sources into the source directory.
|
||||
This rearranges the source files under the python distribution
|
||||
directory.
|
||||
"""
|
||||
src = []
|
||||
|
||||
shutil.rmtree(SRC_DIR, ignore_errors=True)
|
||||
os.mkdir(SRC_DIR)
|
||||
|
||||
@ -66,17 +55,16 @@ def copy_sources():
|
||||
shutil.copytree(os.path.join(ROOT_DIR, '../../samples'), os.path.join(SRC_DIR, 'samples/'))
|
||||
shutil.copytree(os.path.join(ROOT_DIR, '../../glib_compat'), os.path.join(SRC_DIR, 'glib_compat/'))
|
||||
shutil.copytree(os.path.join(ROOT_DIR, '../../cmake'), os.path.join(SRC_DIR, 'cmake/'))
|
||||
|
||||
|
||||
try:
|
||||
# remove site-specific configuration file
|
||||
# might not exist
|
||||
# remove site-specific configuration file, might not exist
|
||||
os.remove(os.path.join(SRC_DIR, 'qemu/config-host.mak'))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
src = []
|
||||
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../*.[ch]")))
|
||||
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../*.mk")))
|
||||
|
||||
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../LICENSE*")))
|
||||
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../README.md")))
|
||||
src.extend(glob.glob(os.path.join(ROOT_DIR, "../../*.TXT")))
|
||||
@ -87,6 +75,7 @@ def copy_sources():
|
||||
log.info("%s -> %s" % (filename, outpath))
|
||||
shutil.copy(filename, outpath)
|
||||
|
||||
|
||||
def build_libraries():
|
||||
"""
|
||||
Prepare the unicorn directory for a binary distribution or installation.
|
||||
@ -94,7 +83,6 @@ def build_libraries():
|
||||
|
||||
Will use a src/ dir if one exists in the current directory, otherwise assumes it's in the repo
|
||||
"""
|
||||
cwd = os.getcwd()
|
||||
clean_bins()
|
||||
os.mkdir(HEADERS_DIR)
|
||||
os.mkdir(LIBS_DIR)
|
||||
@ -102,158 +90,84 @@ def build_libraries():
|
||||
# copy public headers
|
||||
shutil.copytree(os.path.join(UC_DIR, 'include', 'unicorn'), os.path.join(HEADERS_DIR, 'unicorn'))
|
||||
|
||||
# check if a prebuilt library exists
|
||||
# if so, use it instead of building
|
||||
# check if a prebuilt library exists and if so, use it instead of building
|
||||
if os.path.exists(os.path.join(ROOT_DIR, 'prebuilt', LIBRARY_FILE)):
|
||||
shutil.copy(os.path.join(ROOT_DIR, 'prebuilt', LIBRARY_FILE), LIBS_DIR)
|
||||
if STATIC_LIBRARY_FILE is not None and os.path.exists(os.path.join(ROOT_DIR, 'prebuilt', STATIC_LIBRARY_FILE)):
|
||||
shutil.copy(os.path.join(ROOT_DIR, 'prebuilt', STATIC_LIBRARY_FILE), LIBS_DIR)
|
||||
return
|
||||
|
||||
# otherwise, build!!
|
||||
os.chdir(UC_DIR)
|
||||
# otherwise, build
|
||||
if not os.path.exists(BUILD_DIR):
|
||||
os.mkdir(BUILD_DIR)
|
||||
|
||||
try:
|
||||
subprocess.check_call(['msbuild', '/help'])
|
||||
except:
|
||||
has_msbuild = False
|
||||
else:
|
||||
has_msbuild = True
|
||||
has_msbuild = shutil.which('msbuild') is not None
|
||||
conf = 'Debug' if int(os.getenv('DEBUG', 0)) else 'Release'
|
||||
|
||||
if has_msbuild and SYSTEM == 'win32':
|
||||
if has_msbuild and sys.platform == 'win32':
|
||||
plat = 'Win32' if platform.architecture()[0] == '32bit' else 'x64'
|
||||
conf = 'Debug' if os.getenv('DEBUG', '') else 'Release'
|
||||
if not os.path.exists(BUILD_DIR):
|
||||
os.mkdir(BUILD_DIR)
|
||||
|
||||
subprocess.check_call(['cmake', '-B', BUILD_DIR, '-G', "Visual Studio 16 2019", "-A", plat, "-DCMAKE_BUILD_TYPE=" + conf])
|
||||
subprocess.check_call(['msbuild', 'unicorn.sln', '-m', '-p:Platform=' + plat, '-p:Configuration=' + conf], cwd=BUILD_DIR)
|
||||
|
||||
subprocess.check_call(['cmake', '-B', BUILD_DIR, '-G', "Visual Studio 16 2019", "-A", plat,
|
||||
"-DCMAKE_BUILD_TYPE=" + conf], cwd=UC_DIR)
|
||||
subprocess.check_call(['msbuild', 'unicorn.sln', '-m', '-p:Platform=' + plat, '-p:Configuration=' + conf],
|
||||
cwd=BUILD_DIR)
|
||||
|
||||
obj_dir = os.path.join(BUILD_DIR, conf)
|
||||
shutil.copy(os.path.join(obj_dir, LIBRARY_FILE), LIBS_DIR)
|
||||
shutil.copy(os.path.join(BUILD_DIR, STATIC_LIBRARY_FILE), LIBS_DIR)
|
||||
else:
|
||||
# platform description refs at https://docs.python.org/2/library/sys.html#sys.platform
|
||||
if not os.path.exists(BUILD_DIR):
|
||||
os.mkdir(BUILD_DIR)
|
||||
conf = 'Debug' if os.getenv('DEBUG', '') else 'Release'
|
||||
|
||||
cmake_args = ["cmake", '-B', BUILD_DIR, '-S', UC_DIR, "-DCMAKE_BUILD_TYPE=" + conf]
|
||||
if os.getenv("TRACE", ""):
|
||||
if os.getenv("TRACE"):
|
||||
cmake_args += ["-DUNICORN_TRACER=on"]
|
||||
subprocess.check_call(cmake_args)
|
||||
os.chdir(BUILD_DIR)
|
||||
subprocess.check_call(cmake_args, cwd=UC_DIR)
|
||||
threads = os.getenv("THREADS", "4")
|
||||
subprocess.check_call(["cmake", "--build", ".", "-j" + threads])
|
||||
|
||||
shutil.copy(LIBRARY_FILE, LIBS_DIR)
|
||||
shutil.copy(STATIC_LIBRARY_FILE, LIBS_DIR)
|
||||
subprocess.check_call(["cmake", "--build", ".", "-j" + threads], cwd=BUILD_DIR)
|
||||
|
||||
os.chdir(cwd)
|
||||
shutil.copy(os.path.join(BUILD_DIR, LIBRARY_FILE), LIBS_DIR)
|
||||
shutil.copy(os.path.join(BUILD_DIR, STATIC_LIBRARY_FILE), LIBS_DIR)
|
||||
|
||||
|
||||
class custom_sdist(sdist):
|
||||
class CustomSDist(sdist):
|
||||
def run(self):
|
||||
clean_bins()
|
||||
copy_sources()
|
||||
return sdist.run(self)
|
||||
return super().run()
|
||||
|
||||
class custom_build(build):
|
||||
|
||||
class CustomBuild(build):
|
||||
def run(self):
|
||||
if 'LIBUNICORN_PATH' in os.environ:
|
||||
log.info("Skipping building C extensions since LIBUNICORN_PATH is set")
|
||||
else:
|
||||
log.info("Building C extensions")
|
||||
build_libraries()
|
||||
return build.run(self)
|
||||
return super().run()
|
||||
|
||||
class custom_bdist_egg(bdist_egg):
|
||||
|
||||
class CustomBDistEgg(bdist_egg):
|
||||
def run(self):
|
||||
self.run_command('build')
|
||||
return bdist_egg.run(self)
|
||||
return super().run()
|
||||
|
||||
def dummy_src():
|
||||
return []
|
||||
|
||||
cmdclass = {}
|
||||
cmdclass['build'] = custom_build
|
||||
cmdclass['sdist'] = custom_sdist
|
||||
cmdclass['bdist_egg'] = custom_bdist_egg
|
||||
|
||||
if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv:
|
||||
idx = sys.argv.index('bdist_wheel') + 1
|
||||
sys.argv.insert(idx, '--plat-name')
|
||||
name = get_platform()
|
||||
if 'linux' in name:
|
||||
# linux_* platform tags are disallowed because the python ecosystem is fubar
|
||||
# linux builds should be built in the centos 5 vm for maximum compatibility
|
||||
# see https://github.com/pypa/manylinux
|
||||
# see also https://github.com/angr/angr-dev/blob/master/bdist.sh
|
||||
sys.argv.insert(idx + 1, 'manylinux1_' + platform.machine())
|
||||
elif 'mingw' in name:
|
||||
if IS_64BITS:
|
||||
sys.argv.insert(idx + 1, 'win_amd64')
|
||||
else:
|
||||
sys.argv.insert(idx + 1, 'win32')
|
||||
else:
|
||||
# https://www.python.org/dev/peps/pep-0425/
|
||||
sys.argv.insert(idx + 1, name.replace('.', '_').replace('-', '_'))
|
||||
cmdclass = {'build': CustomBuild, 'sdist': CustomSDist, 'bdist_egg': CustomBDistEgg}
|
||||
|
||||
try:
|
||||
from setuptools.command.develop import develop
|
||||
class custom_develop(develop):
|
||||
|
||||
|
||||
class CustomDevelop(develop):
|
||||
def run(self):
|
||||
log.info("Building C extensions")
|
||||
build_libraries()
|
||||
return develop.run(self)
|
||||
return super().run()
|
||||
|
||||
cmdclass['develop'] = custom_develop
|
||||
|
||||
cmdclass['develop'] = CustomDevelop
|
||||
except ImportError:
|
||||
print("Proper 'develop' support unavailable.")
|
||||
|
||||
def join_all(src, files):
|
||||
return tuple(os.path.join(src, f) for f in files)
|
||||
|
||||
long_desc = '''
|
||||
Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framework
|
||||
based on [QEMU](http://qemu.org).
|
||||
|
||||
Unicorn offers some unparalleled features:
|
||||
|
||||
- Multi-architecture: ARM, ARM64 (ARMv8), M68K, MIPS, PowerPC, RISCV, SPARC, S390X, TriCore and X86 (16, 32, 64-bit)
|
||||
- Clean/simple/lightweight/intuitive architecture-neutral API
|
||||
- Implemented in pure C language, with bindings for Crystal, Clojure, Visual Basic, Perl, Rust, Ruby, Python, Java, .NET, Go, Delphi/Free Pascal, Haskell, Pharo, and Lua.
|
||||
- Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed)
|
||||
- High performance via Just-In-Time compilation
|
||||
- Support for fine-grained instrumentation at various levels
|
||||
- Thread-safety by design
|
||||
- Distributed under free software license GPLv2
|
||||
|
||||
Further information is available at http://www.unicorn-engine.org
|
||||
'''
|
||||
|
||||
setup(
|
||||
provides=['unicorn'],
|
||||
packages=setuptools.find_packages(include=["unicorn", "unicorn.*"]),
|
||||
name='unicorn',
|
||||
version=VERSION,
|
||||
author='Nguyen Anh Quynh',
|
||||
author_email='aquynh@gmail.com',
|
||||
description='Unicorn CPU emulator engine',
|
||||
long_description=long_desc,
|
||||
long_description_content_type="text/markdown",
|
||||
url='http://www.unicorn-engine.org',
|
||||
classifiers=[
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 3',
|
||||
],
|
||||
requires=['ctypes'],
|
||||
cmdclass=cmdclass,
|
||||
zip_safe=False,
|
||||
include_package_data=True,
|
||||
is_pure=False,
|
||||
package_data={
|
||||
'unicorn': ['unicorn/py.typed', 'lib/*', 'include/unicorn/*']
|
||||
}
|
||||
has_ext_modules=lambda: True, # It's not a Pure Python wheel
|
||||
)
|
||||
|
@ -6,22 +6,21 @@ from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.arm_const import *
|
||||
|
||||
|
||||
# code to be emulated
|
||||
ARM_CODE = b"\x37\x00\xa0\xe3\x03\x10\x42\xe0" # mov r0, #0x37; sub r1, r2, r3
|
||||
THUMB_CODE = b"\x83\xb0" # sub sp, #0xc
|
||||
ARM_CODE = b"\x37\x00\xa0\xe3\x03\x10\x42\xe0" # mov r0, #0x37; sub r1, r2, r3
|
||||
THUMB_CODE = b"\x83\xb0" # sub sp, #0xc
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# Test ARM
|
||||
@ -41,8 +40,8 @@ def test_arm():
|
||||
mu.reg_write(UC_ARM_REG_R0, 0x1234)
|
||||
mu.reg_write(UC_ARM_REG_R2, 0x6789)
|
||||
mu.reg_write(UC_ARM_REG_R3, 0x3333)
|
||||
mu.reg_write(UC_ARM_REG_APSR, 0xFFFFFFFF) #All application flags turned on
|
||||
|
||||
mu.reg_write(UC_ARM_REG_APSR, 0xFFFFFFFF) # All application flags turned on
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
@ -57,8 +56,8 @@ def test_arm():
|
||||
|
||||
r0 = mu.reg_read(UC_ARM_REG_R0)
|
||||
r1 = mu.reg_read(UC_ARM_REG_R1)
|
||||
print(">>> R0 = 0x%x" %r0)
|
||||
print(">>> R1 = 0x%x" %r1)
|
||||
print(">>> R0 = 0x%x" % r0)
|
||||
print(">>> R1 = 0x%x" % r1)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
@ -93,11 +92,12 @@ def test_thumb():
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
sp = mu.reg_read(UC_ARM_REG_SP)
|
||||
print(">>> SP = 0x%x" %sp)
|
||||
print(">>> SP = 0x%x" % sp)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_read_sctlr():
|
||||
print("Read SCTLR")
|
||||
try:
|
||||
@ -118,6 +118,7 @@ def test_read_sctlr():
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_arm()
|
||||
print("=" * 26)
|
@ -6,25 +6,24 @@ from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.arm64_const import *
|
||||
|
||||
|
||||
# code to be emulated
|
||||
ARM64_CODE = b"\xab\x05\x00\xb8\xaf\x05\x40\x38" # str x11, [x13]; ldrb x15, [x13]
|
||||
ARM64_CODE = b"\xab\x05\x00\xb8\xaf\x05\x40\x38" # str x11, [x13]; ldrb x15, [x13]
|
||||
|
||||
# MSR code
|
||||
ARM64_MRS_CODE = b"\x62\xd0\x3b\xd5" # mrs x2, tpidrro_el0
|
||||
ARM64_MRS_CODE = b"\x62\xd0\x3b\xd5" # mrs x2, tpidrro_el0
|
||||
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# Test ARM64
|
||||
@ -61,7 +60,7 @@ def test_arm64():
|
||||
x11 = mu.reg_read(UC_ARM64_REG_X11)
|
||||
x13 = mu.reg_read(UC_ARM64_REG_X13)
|
||||
x15 = mu.reg_read(UC_ARM64_REG_X15)
|
||||
print(">>> X15 = 0x%x" %x15)
|
||||
print(">>> X15 = 0x%x" % x15)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
@ -85,6 +84,7 @@ def test_arm64_read_sctlr():
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_arm64_hook_mrs():
|
||||
def _hook_mrs(uc, reg, cp_reg, _):
|
||||
print(f">>> Hook MRS instruction: reg = 0x{reg:x}(UC_ARM64_REG_X2) cp_reg = {cp_reg}")
|
||||
@ -116,6 +116,7 @@ def test_arm64_hook_mrs():
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_arm64()
|
||||
print("=" * 26)
|
@ -7,22 +7,21 @@ from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.arm64_const import *
|
||||
|
||||
|
||||
# code to be emulated
|
||||
ARM64_CODE = b"\xab\x05\x00\xb8\xaf\x05\x40\x38" # str x11, [x13]; ldrb x15, [x13]
|
||||
ARM64_CODE = b"\xab\x05\x00\xb8\xaf\x05\x40\x38" # str x11, [x13]; ldrb x15, [x13]
|
||||
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# Test ARM64
|
||||
@ -59,7 +58,7 @@ def test_arm64():
|
||||
x11 = mu.reg_read(UC_ARM64_REG_X11)
|
||||
x13 = mu.reg_read(UC_ARM64_REG_X13)
|
||||
x15 = mu.reg_read(UC_ARM64_REG_X15)
|
||||
print(">>> X15 = 0x%x" %x15)
|
||||
print(">>> X15 = 0x%x" % x15)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
@ -5,22 +5,21 @@ from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.arm_const import *
|
||||
|
||||
|
||||
# code to be emulated
|
||||
ARM_CODE = b"\xe3\xa0\x00\x37\xe0\x42\x10\x03" # mov r0, #0x37; sub r1, r2, r3
|
||||
THUMB_CODE = b"\xb0\x83" # sub sp, #0xc
|
||||
ARM_CODE = b"\xe3\xa0\x00\x37\xe0\x42\x10\x03" # mov r0, #0x37; sub r1, r2, r3
|
||||
THUMB_CODE = b"\xb0\x83" # sub sp, #0xc
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# Test ARM
|
||||
@ -40,8 +39,8 @@ def test_arm():
|
||||
mu.reg_write(UC_ARM_REG_R0, 0x1234)
|
||||
mu.reg_write(UC_ARM_REG_R2, 0x6789)
|
||||
mu.reg_write(UC_ARM_REG_R3, 0x3333)
|
||||
mu.reg_write(UC_ARM_REG_APSR, 0xFFFFFFFF) #All application flags turned on
|
||||
|
||||
mu.reg_write(UC_ARM_REG_APSR, 0xFFFFFFFF) # All application flags turned on
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
@ -56,8 +55,8 @@ def test_arm():
|
||||
|
||||
r0 = mu.reg_read(UC_ARM_REG_R0)
|
||||
r1 = mu.reg_read(UC_ARM_REG_R1)
|
||||
print(">>> R0 = 0x%x" %r0)
|
||||
print(">>> R1 = 0x%x" %r1)
|
||||
print(">>> R0 = 0x%x" % r0)
|
||||
print(">>> R1 = 0x%x" % r1)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
@ -92,7 +91,7 @@ def test_thumb():
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
sp = mu.reg_read(UC_ARM_REG_SP)
|
||||
print(">>> SP = 0x%x" %sp)
|
||||
print(">>> SP = 0x%x" % sp)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
@ -6,6 +6,7 @@ from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def test_uc_ctl_read():
|
||||
uc = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
@ -21,6 +22,7 @@ def test_uc_ctl_read():
|
||||
|
||||
print(f">>> arch={arch} mode={mode} page size={page_size} timeout={timeout}")
|
||||
|
||||
|
||||
def time_emulation(uc, start, end):
|
||||
n = datetime.now()
|
||||
|
||||
@ -28,6 +30,7 @@ def time_emulation(uc, start, end):
|
||||
|
||||
return (datetime.now() - n).total_seconds() * 1e6
|
||||
|
||||
|
||||
def test_uc_ctl_tb_cache():
|
||||
# Initialize emulator in X86-32bit mode
|
||||
uc = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
@ -35,21 +38,21 @@ def test_uc_ctl_tb_cache():
|
||||
|
||||
# Fill the code buffer with NOP.
|
||||
code = b"\x90" * 8 * 512
|
||||
|
||||
print("Controling the TB cache in a finer granularity by uc_ctl.")
|
||||
|
||||
print("Controlling the TB cache in a finer granularity by uc_ctl.")
|
||||
|
||||
uc.mem_map(addr, 0x10000)
|
||||
|
||||
# Write our code to the memory.
|
||||
uc.mem_write(addr, code)
|
||||
|
||||
|
||||
# Do emulation without any cache.
|
||||
standard = time_emulation(uc, addr, addr + len(code))
|
||||
|
||||
# Now we request cache for all TBs.
|
||||
for i in range(8):
|
||||
tb = uc.ctl_request_cache(addr + i * 512)
|
||||
print(f">>> TB is cached at {hex(tb.pc)} which has {tb.icount} instructions with {tb.size} bytes")
|
||||
print(f">>> TB is cached at {hex(tb[0])} which has {tb[1]} instructions with {tb[2]} bytes")
|
||||
|
||||
# Do emulation with all TB cached.
|
||||
cached = time_emulation(uc, addr, addr + len(code))
|
||||
@ -62,12 +65,15 @@ def test_uc_ctl_tb_cache():
|
||||
|
||||
print(f">>> Run time: First time {standard}, Cached: {cached}, Cached evicted: {evicted}")
|
||||
|
||||
|
||||
def trace_new_edge(uc, cur, prev, data):
|
||||
print(f">>> Getting a new edge from {hex(prev.pc + prev.size - 1)} to {hex(cur.pc)}")
|
||||
|
||||
|
||||
def trace_tcg_sub(uc, address, arg1, arg2, size, data):
|
||||
print(f">>> Get a tcg sub opcode at {hex(address)} with args: {arg1} and {arg2}")
|
||||
|
||||
|
||||
def test_uc_ctl_exits():
|
||||
uc = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
addr = 0x1000
|
||||
@ -98,7 +104,7 @@ def test_uc_ctl_exits():
|
||||
|
||||
uc.ctl_set_exits(exits)
|
||||
|
||||
# This should stop at ADDRESS + 6 and increase eax, even thouhg we don't provide an exit.
|
||||
# This should stop at ADDRESS + 6 and increase eax, even though we don't provide an exit.
|
||||
uc.emu_start(addr, 0)
|
||||
|
||||
eax = uc.reg_read(UC_X86_REG_EAX)
|
||||
@ -106,7 +112,7 @@ def test_uc_ctl_exits():
|
||||
|
||||
print(f">>> eax = {hex(eax)} and ebx = {hex(ebx)} after the first emulation")
|
||||
|
||||
# This should stop at ADDRESS + 8, even thouhg we don't provide an exit.
|
||||
# This should stop at ADDRESS + 8, even though we don't provide an exit.
|
||||
uc.emu_start(addr, 0)
|
||||
|
||||
eax = uc.reg_read(UC_X86_REG_EAX)
|
||||
@ -114,9 +120,10 @@ def test_uc_ctl_exits():
|
||||
|
||||
print(f">>> eax = {hex(eax)} and ebx = {hex(ebx)} after the first emulation")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_uc_ctl_read()
|
||||
print("="*32)
|
||||
print("=" * 32)
|
||||
test_uc_ctl_tb_cache()
|
||||
print("="*32)
|
||||
test_uc_ctl_exits()
|
||||
print("=" * 32)
|
||||
test_uc_ctl_exits()
|
@ -6,21 +6,20 @@ from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.m68k_const import *
|
||||
|
||||
|
||||
# code to be emulated
|
||||
M68K_CODE = b"\x76\xed" # movq #-19, %d3
|
||||
M68K_CODE = b"\x76\xed" # movq #-19, %d3
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# Test ARM
|
@ -6,23 +6,22 @@ from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.mips_const import *
|
||||
|
||||
|
||||
# code to be emulated
|
||||
MIPS_CODE_EB = b"\x34\x21\x34\x56" # ori $at, $at, 0x3456;
|
||||
MIPS_CODE_EL = b"\x56\x34\x21\x34" # ori $at, $at, 0x3456;
|
||||
MIPS_CODE_EB = b"\x34\x21\x34\x56" # ori $at, $at, 0x3456;
|
||||
MIPS_CODE_EL = b"\x56\x34\x21\x34" # ori $at, $at, 0x3456;
|
||||
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# Test MIPS EB
|
||||
@ -54,7 +53,7 @@ def test_mips_eb():
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r1 = mu.reg_read(UC_MIPS_REG_1)
|
||||
print(">>> R1 = 0x%x" %r1)
|
||||
print(">>> R1 = 0x%x" % r1)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
@ -89,7 +88,7 @@ def test_mips_el():
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r1 = mu.reg_read(UC_MIPS_REG_1)
|
||||
print(">>> R1 = 0x%x" %r1)
|
||||
print(">>> R1 = 0x%x" % r1)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
@ -3,10 +3,11 @@
|
||||
# Nguyen Tan Cong <shenlongbk@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
import pytest
|
||||
import struct
|
||||
import uuid
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
|
||||
SIZE_REG = 4
|
||||
SOCKETCALL_MAX_ARGS = 3
|
||||
@ -360,6 +361,7 @@ def hook_intr(uc, intno, user_data):
|
||||
print_sockcall(msg)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("code", [X86_SEND_ETCPASSWD, X86_BIND_TCP, X86_REVERSE_TCP, X86_REVERSE_TCP_2])
|
||||
# Test X86 32 bit
|
||||
def test_i386(code):
|
||||
global fd_chains
|
@ -1,26 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
# Sample code for PPC of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.ppc_const import *
|
||||
|
||||
|
||||
# code to be emulated
|
||||
PPC_CODE = b"\x7F\x46\x1A\x14" # add r26, r6, r3
|
||||
PPC_CODE = b"\x7F\x46\x1A\x14" # add r26, r6, r3
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# Test PPC
|
||||
@ -62,4 +60,3 @@ def test_ppc():
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_ppc()
|
||||
|
@ -1,12 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
# Sample code for RISCV of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.riscv_const import *
|
||||
|
||||
|
||||
'''
|
||||
$ cstool riscv64 1305100093850502
|
||||
0 13 05 10 00 addi a0, zero, 1
|
||||
@ -15,17 +13,17 @@ $ cstool riscv64 1305100093850502
|
||||
RISCV_CODE = b"\x13\x05\x10\x00\x93\x85\x05\x02"
|
||||
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# Test RISCV
|
||||
@ -59,8 +57,8 @@ def test_riscv():
|
||||
|
||||
a0 = mu.reg_read(UC_RISCV_REG_A0)
|
||||
a1 = mu.reg_read(UC_RISCV_REG_A1)
|
||||
print(">>> A0 = 0x%x" %a0)
|
||||
print(">>> A1 = 0x%x" %a1)
|
||||
print(">>> A0 = 0x%x" % a0)
|
||||
print(">>> A1 = 0x%x" % a1)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
@ -68,4 +66,3 @@ def test_riscv():
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_riscv()
|
||||
|
@ -8,17 +8,17 @@ from unicorn.s390x_const import *
|
||||
S390X_CODE = b"\x18\x23"
|
||||
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# Test RISCV
|
||||
@ -60,4 +60,3 @@ def test_s390x():
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_s390x()
|
||||
|
@ -4,11 +4,12 @@
|
||||
# KaiJern Lau <kj@theshepherdlab.io>
|
||||
|
||||
from __future__ import print_function
|
||||
import pytest
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
|
||||
# Original shellcode from this example.
|
||||
#X86_CODE32 = b"\xeb\x19\x31\xc0\x31\xdb\x31\xd2\x31\xc9\xb0\x04\xb3\x01\x59\xb2\x05\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\xe2\xff\xff\xff\x68\x65\x6c\x6c\x6f"
|
||||
# X86_CODE32 = b"\xeb\x19\x31\xc0\x31\xdb\x31\xd2\x31\xc9\xb0\x04\xb3\x01\x59\xb2\x05\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\xe2\xff\xff\xff\x68\x65\x6c\x6c\x6f"
|
||||
|
||||
# Linux/x86 execve /bin/sh shellcode 23 bytes, from http://shell-storm.org/shellcode/files/shellcode-827.php
|
||||
# 0: 31 c0 xor eax,eax
|
||||
@ -44,20 +45,22 @@ X86_CODE64 = b"\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x1000000
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
# read this instruction code from memory
|
||||
tmp = uc.mem_read(address, size)
|
||||
print("*** PC = %x *** :" %(address), end="")
|
||||
print("*** PC = %x *** :" % (address), end="")
|
||||
for i in tmp:
|
||||
print(" %02x" %i, end="")
|
||||
print(" %02x" % i, end="")
|
||||
print("")
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
def read_string(uc, address):
|
||||
ret = ""
|
||||
@ -70,21 +73,22 @@ def read_string(uc, address):
|
||||
read_bytes += 1
|
||||
return ret
|
||||
|
||||
|
||||
# callback for tracing Linux interrupt
|
||||
def hook_intr(uc, intno, user_data):
|
||||
# only handle Linux syscall
|
||||
if intno != 0x80:
|
||||
print("got interrupt %x ???" %intno)
|
||||
print("got interrupt %x ???" % intno)
|
||||
uc.emu_stop()
|
||||
return
|
||||
|
||||
eax = uc.reg_read(UC_X86_REG_EAX)
|
||||
eip = uc.reg_read(UC_X86_REG_EIP)
|
||||
|
||||
if eax == 1: # sys_exit
|
||||
print(">>> 0x%x: interrupt 0x%x, EAX = 0x%x" %(eip, intno, eax))
|
||||
if eax == 1: # sys_exit
|
||||
print(">>> 0x%x: interrupt 0x%x, EAX = 0x%x" % (eip, intno, eax))
|
||||
uc.emu_stop()
|
||||
elif eax == 4: # sys_write
|
||||
elif eax == 4: # sys_write
|
||||
# ECX = buffer address
|
||||
ecx = uc.reg_read(UC_X86_REG_ECX)
|
||||
# EDX = buffer size
|
||||
@ -92,49 +96,53 @@ def hook_intr(uc, intno, user_data):
|
||||
try:
|
||||
buf = uc.mem_read(ecx, edx)
|
||||
print(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u, content = " \
|
||||
%(eip, intno, ecx, edx), end="")
|
||||
% (eip, intno, ecx, edx), end="")
|
||||
for i in buf:
|
||||
print("%c" %i, end="")
|
||||
print("%c" % i, end="")
|
||||
print("")
|
||||
except UcError as e:
|
||||
print(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u, content = <unknown>\n" \
|
||||
%(eip, intno, ecx, edx))
|
||||
elif eax == 11: # sys_write
|
||||
% (eip, intno, ecx, edx))
|
||||
elif eax == 11: # sys_write
|
||||
ebx = uc.reg_read(UC_X86_REG_EBX)
|
||||
filename = read_string(uc, ebx)
|
||||
print(">>> SYS_EXECV filename=%s" % filename)
|
||||
else:
|
||||
print(">>> 0x%x: interrupt 0x%x, EAX = 0x%x" %(eip, intno, eax))
|
||||
print(">>> 0x%x: interrupt 0x%x, EAX = 0x%x" % (eip, intno, eax))
|
||||
|
||||
|
||||
def hook_syscall32(mu, user_data):
|
||||
eax = mu.reg_read(UC_X86_REG_EAX)
|
||||
print(">>> got SYSCALL with EAX = 0x%x" %(eax))
|
||||
print(">>> got SYSCALL with EAX = 0x%x" % (eax))
|
||||
mu.emu_stop()
|
||||
|
||||
|
||||
def hook_syscall64(mu, user_data):
|
||||
rax = mu.reg_read(UC_X86_REG_RAX)
|
||||
rdi = mu.reg_read(UC_X86_REG_RDI)
|
||||
|
||||
print(">>> got SYSCALL with RAX = %d" %(rax))
|
||||
|
||||
if rax == 59: #sys_execve
|
||||
print(">>> got SYSCALL with RAX = %d" % (rax))
|
||||
|
||||
if rax == 59: # sys_execve
|
||||
filename = read_string(mu, rdi)
|
||||
print(">>> SYS_EXECV filename=%s" % filename)
|
||||
|
||||
else:
|
||||
rip = mu.reg_read(UC_X86_REG_RIP)
|
||||
print(">>> Syscall Found at 0x%x: , RAX = 0x%x" %(rip, rax))
|
||||
print(">>> Syscall Found at 0x%x: , RAX = 0x%x" % (rip, rax))
|
||||
|
||||
mu.emu_stop()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode,code",
|
||||
[(UC_MODE_32, X86_CODE32_SELF), (UC_MODE_32, X86_CODE32), (UC_MODE_64, X86_CODE64)])
|
||||
# Test X86 32 bit
|
||||
def test_i386(mode, code):
|
||||
if mode == UC_MODE_32:
|
||||
print("Emulate x86_32 code")
|
||||
elif mode == UC_MODE_64:
|
||||
print("Emulate x86_64 code")
|
||||
|
||||
|
||||
try:
|
||||
# Initialize emulator
|
||||
mu = Uc(UC_ARCH_X86, mode)
|
||||
@ -171,9 +179,10 @@ def test_i386(mode, code):
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_i386(UC_MODE_32, X86_CODE32_SELF)
|
||||
print("=" * 20)
|
||||
test_i386(UC_MODE_32, X86_CODE32)
|
||||
print("=" * 20)
|
||||
test_i386(UC_MODE_64, X86_CODE64)
|
||||
test_i386(UC_MODE_64, X86_CODE64)
|
@ -6,21 +6,20 @@ from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.sparc_const import *
|
||||
|
||||
|
||||
# code to be emulated
|
||||
SPARC_CODE = b"\x86\x00\x40\x02" # add %g1, %g2, %g3;
|
||||
SPARC_CODE = b"\x86\x00\x40\x02" # add %g1, %g2, %g3;
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# Test SPARC
|
||||
@ -28,7 +27,7 @@ def test_sparc():
|
||||
print("Emulate SPARC code")
|
||||
try:
|
||||
# Initialize emulator in SPARC EB mode
|
||||
mu = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN)
|
||||
mu = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32 | UC_MODE_BIG_ENDIAN)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
@ -54,7 +53,7 @@ def test_sparc():
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
g3 = mu.reg_read(UC_SPARC_REG_G3)
|
||||
print(">>> G3 = 0x%x" %g3)
|
||||
print(">>> G3 = 0x%x" % g3)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
@ -1,26 +1,29 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
'''
|
||||
"""
|
||||
Created for Unicorn Engine by Eric Poole <eric.poole@aptiv.com>, 2022
|
||||
Copyright 2022 Aptiv
|
||||
'''
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.tricore_const import *
|
||||
|
||||
# code to be emulated
|
||||
TRICORE_CODE = b"\x82\x11\xbb\x00\x00\x08" # mov d0, #0x1; mov.u d0, #0x8000
|
||||
TRICORE_CODE = b"\x82\x11\xbb\x00\x00\x08" # mov d0, #0x1; mov.u d0, #0x8000
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# Test TriCore
|
||||
def test_tricore():
|
||||
@ -48,10 +51,11 @@ def test_tricore():
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r0 = mu.reg_read(UC_TRICORE_REG_D0)
|
||||
print(">>> D0 = 0x%x" %r0)
|
||||
print(">>> D0 = 0x%x" % r0)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_tricore()
|
@ -2,21 +2,21 @@
|
||||
# Sample code for X86 of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
import pickle
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
import pickle
|
||||
|
||||
X86_CODE32 = b"\x41\x4a\x66\x0f\xef\xc1" # INC ecx; DEC edx; PXOR xmm0, xmm1
|
||||
X86_CODE32_LOOP = b"\x41\x4a\xeb\xfe" # INC ecx; DEC edx; JMP self-loop
|
||||
X86_CODE32_JUMP = b"\xeb\x02\x90\x90\x90\x90\x90\x90" # jmp 4; nop; nop; nop; nop; nop; nop
|
||||
X86_CODE32_JMP_INVALID = b"\xe9\xe9\xee\xee\xee\x41\x4a" # JMP outside; INC ecx; DEC edx
|
||||
X86_CODE32_MEM_READ = b"\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx
|
||||
X86_CODE32_MEM_WRITE = b"\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov [0xaaaaaaaa], ecx; INC ecx; DEC edx
|
||||
X86_CODE32 = b"\x41\x4a\x66\x0f\xef\xc1" # INC ecx; DEC edx; PXOR xmm0, xmm1
|
||||
X86_CODE32_LOOP = b"\x41\x4a\xeb\xfe" # INC ecx; DEC edx; JMP self-loop
|
||||
X86_CODE32_JUMP = b"\xeb\x02\x90\x90\x90\x90\x90\x90" # jmp 4; nop; nop; nop; nop; nop; nop
|
||||
X86_CODE32_JMP_INVALID = b"\xe9\xe9\xee\xee\xee\x41\x4a" # JMP outside; INC ecx; DEC edx
|
||||
X86_CODE32_MEM_READ = b"\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx
|
||||
X86_CODE32_MEM_WRITE = b"\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov [0xaaaaaaaa], ecx; INC ecx; DEC edx
|
||||
X86_CODE64 = b"\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9\x4D\x29\xF4\x49\x81\xC9\xF6\x8A\xC6\x53\x4D\x87\xED\x48\x0F\xAD\xD2\x49\xF7\xD4\x48\xF7\xE1\x4D\x19\xC5\x4D\x89\xC5\x48\xF7\xD6\x41\xB8\x4F\x8D\x6B\x59\x4D\x87\xD0\x68\x6A\x1E\x09\x3C\x59"
|
||||
X86_CODE32_INOUT = b"\x41\xE4\x3F\x4a\xE6\x46\x43" # INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx
|
||||
X86_CODE64_SYSCALL = b'\x0f\x05' # SYSCALL
|
||||
X86_CODE16 = b'\x00\x00' # add byte ptr [bx + si], al
|
||||
X86_MMIO_CODE = b"\x89\x0d\x04\x00\x02\x00\x8b\x0d\x04\x00\x02\x00" # mov [0x20004], ecx; mov ecx, [0x20004]
|
||||
X86_CODE32_INOUT = b"\x41\xE4\x3F\x4a\xE6\x46\x43" # INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx
|
||||
X86_CODE64_SYSCALL = b'\x0f\x05' # SYSCALL
|
||||
X86_CODE16 = b'\x00\x00' # add byte ptr [bx + si], al
|
||||
X86_MMIO_CODE = b"\x89\x0d\x04\x00\x02\x00\x8b\x0d\x04\x00\x02\x00" # mov [0x20004], ecx; mov ecx, [0x20004]
|
||||
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x1000000
|
||||
@ -24,28 +24,29 @@ ADDRESS = 0x1000000
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" % (address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
eflags = uc.reg_read(UC_X86_REG_EFLAGS)
|
||||
print(">>> --- EFLAGS is 0x%x" %eflags)
|
||||
print(">>> --- EFLAGS is 0x%x" % eflags)
|
||||
|
||||
|
||||
def hook_code64(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
rip = uc.reg_read(UC_X86_REG_RIP)
|
||||
print(">>> RIP is 0x%x" %rip)
|
||||
print(">>> RIP is 0x%x" % rip)
|
||||
|
||||
|
||||
# callback for tracing invalid memory access (READ or WRITE)
|
||||
def hook_mem_invalid(uc, access, address, size, value, user_data):
|
||||
if access == UC_MEM_WRITE_UNMAPPED:
|
||||
print(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \
|
||||
%(address, size, value))
|
||||
% (address, size, value))
|
||||
# map this memory in with 2MB in size
|
||||
uc.mem_map(0xaaaa0000, 2 * 1024*1024)
|
||||
uc.mem_map(0xaaaa0000, 2 * 1024 * 1024)
|
||||
# return True to indicate we want to continue emulation
|
||||
return True
|
||||
else:
|
||||
@ -57,16 +58,16 @@ def hook_mem_invalid(uc, access, address, size, value, user_data):
|
||||
def hook_mem_access(uc, access, address, size, value, user_data):
|
||||
if access == UC_MEM_WRITE:
|
||||
print(">>> Memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \
|
||||
%(address, size, value))
|
||||
else: # READ
|
||||
% (address, size, value))
|
||||
else: # READ
|
||||
print(">>> Memory is being READ at 0x%x, data size = %u" \
|
||||
%(address, size))
|
||||
% (address, size))
|
||||
|
||||
|
||||
# callback for IN instruction
|
||||
def hook_in(uc, port, size, user_data):
|
||||
eip = uc.reg_read(UC_X86_REG_EIP)
|
||||
print("--- reading from port 0x%x, size: %u, address: 0x%x" %(port, size, eip))
|
||||
print("--- reading from port 0x%x, size: %u, address: 0x%x" % (port, size, eip))
|
||||
if size == 1:
|
||||
# read 1 byte to AL
|
||||
return 0xf1
|
||||
@ -83,7 +84,7 @@ def hook_in(uc, port, size, user_data):
|
||||
# callback for OUT instruction
|
||||
def hook_out(uc, port, size, value, user_data):
|
||||
eip = uc.reg_read(UC_X86_REG_EIP)
|
||||
print("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x" %(port, size, value, eip))
|
||||
print("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x" % (port, size, value, eip))
|
||||
|
||||
# confirm that value is indeed the value of AL/AX/EAX
|
||||
v = 0
|
||||
@ -97,7 +98,7 @@ def hook_out(uc, port, size, value, user_data):
|
||||
# read 4 bytes in EAX
|
||||
v = uc.reg_read(UC_X86_REG_EAX)
|
||||
|
||||
print("--- register value = 0x%x" %v)
|
||||
print("--- register value = 0x%x" % v)
|
||||
|
||||
|
||||
# Test X86 32 bit
|
||||
@ -134,15 +135,15 @@ def test_i386():
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_edx = mu.reg_read(UC_X86_REG_EDX)
|
||||
r_xmm0 = mu.reg_read(UC_X86_REG_XMM0)
|
||||
print(">>> ECX = 0x%x" %r_ecx)
|
||||
print(">>> EDX = 0x%x" %r_edx)
|
||||
print(">>> XMM0 = 0x%.32x" %r_xmm0)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
print(">>> EDX = 0x%x" % r_edx)
|
||||
print(">>> XMM0 = 0x%.32x" % r_xmm0)
|
||||
|
||||
# read from memory
|
||||
tmp = mu.mem_read(ADDRESS, 4)
|
||||
print(">>> Read 4 bytes from [0x%x] = 0x" %(ADDRESS), end="")
|
||||
print(">>> Read 4 bytes from [0x%x] = 0x" % (ADDRESS), end="")
|
||||
for i in reversed(tmp):
|
||||
print("%x" %(i), end="")
|
||||
print("%x" % (i), end="")
|
||||
print("")
|
||||
|
||||
except UcError as e:
|
||||
@ -179,14 +180,14 @@ def test_i386_map_ptr():
|
||||
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_edx = mu.reg_read(UC_X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" %r_ecx)
|
||||
print(">>> EDX = 0x%x" %r_edx)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
print(">>> EDX = 0x%x" % r_edx)
|
||||
|
||||
# read from memory
|
||||
tmp = mu.mem_read(ADDRESS, 4)
|
||||
print(">>> Read 4 bytes from [0x%x] = 0x" %(ADDRESS), end="")
|
||||
print(">>> Read 4 bytes from [0x%x] = 0x" % (ADDRESS), end="")
|
||||
for i in reversed(tmp):
|
||||
print("%x" %(i), end="")
|
||||
print("%x" % (i), end="")
|
||||
print("")
|
||||
|
||||
except UcError as e:
|
||||
@ -226,12 +227,13 @@ def test_i386_invalid_mem_read():
|
||||
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_edx = mu.reg_read(UC_X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" %r_ecx)
|
||||
print(">>> EDX = 0x%x" %r_edx)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
print(">>> EDX = 0x%x" % r_edx)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_i386_jump():
|
||||
print("Emulate i386 code with jump")
|
||||
try:
|
||||
@ -298,22 +300,22 @@ def test_i386_invalid_mem_write():
|
||||
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_edx = mu.reg_read(UC_X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" %r_ecx)
|
||||
print(">>> EDX = 0x%x" %r_edx)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
print(">>> EDX = 0x%x" % r_edx)
|
||||
|
||||
# read from memory
|
||||
print(">>> Read 4 bytes from [0x%x] = 0x" %(0xaaaaaaaa), end="")
|
||||
print(">>> Read 4 bytes from [0x%x] = 0x" % (0xaaaaaaaa), end="")
|
||||
tmp = mu.mem_read(0xaaaaaaaa, 4)
|
||||
for i in reversed(tmp):
|
||||
if i != 0:
|
||||
print("%x" %i, end="")
|
||||
print("%x" % i, end="")
|
||||
print("")
|
||||
|
||||
try:
|
||||
tmp = mu.mem_read(0xffffffaa, 4)
|
||||
print(">>> Read 4 bytes from [0x%x] = 0x" %(0xffffffaa), end="")
|
||||
print(">>> Read 4 bytes from [0x%x] = 0x" % (0xffffffaa), end="")
|
||||
for i in reversed(tmp):
|
||||
print("%x" %i, end="")
|
||||
print("%x" % i, end="")
|
||||
print("")
|
||||
|
||||
except UcError as e:
|
||||
@ -322,6 +324,7 @@ def test_i386_invalid_mem_write():
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_i386_jump_invalid():
|
||||
print("Emulate i386 code that jumps to invalid memory")
|
||||
try:
|
||||
@ -347,18 +350,19 @@ def test_i386_jump_invalid():
|
||||
try:
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_JMP_INVALID))
|
||||
except UcError as e:
|
||||
print("Failed on uc_emu_start() with error returned 8: %s" %e)
|
||||
print("Failed on uc_emu_start() with error returned 8: %s" % e)
|
||||
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_edx = mu.reg_read(UC_X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" %r_ecx)
|
||||
print(">>> EDX = 0x%x" %r_edx)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
print(">>> EDX = 0x%x" % r_edx)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR %s" % e)
|
||||
|
||||
|
||||
def test_i386_loop():
|
||||
print("Emulate i386 code that loop forever")
|
||||
try:
|
||||
@ -375,18 +379,19 @@ def test_i386_loop():
|
||||
mu.reg_write(UC_X86_REG_ECX, 0x1234)
|
||||
mu.reg_write(UC_X86_REG_EDX, 0x7890)
|
||||
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_LOOP), timeout=2*UC_SECOND_SCALE)
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_LOOP), timeout=2 * UC_SECOND_SCALE)
|
||||
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_edx = mu.reg_read(UC_X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" %r_ecx)
|
||||
print(">>> EDX = 0x%x" %r_edx)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
print(">>> EDX = 0x%x" % r_edx)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
# Test X86 32 bit with IN/OUT instruction
|
||||
def test_i386_inout():
|
||||
print("Emulate i386 code with IN/OUT instructions")
|
||||
@ -422,8 +427,8 @@ def test_i386_inout():
|
||||
|
||||
r_ecx = mu.reg_read(UC_X86_REG_ECX)
|
||||
r_eax = mu.reg_read(UC_X86_REG_EAX)
|
||||
print(">>> EAX = 0x%x" %r_eax)
|
||||
print(">>> ECX = 0x%x" %r_ecx)
|
||||
print(">>> EAX = 0x%x" % r_eax)
|
||||
print(">>> ECX = 0x%x" % r_ecx)
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
@ -446,10 +451,10 @@ def test_i386_context_save():
|
||||
mu.reg_write(UC_X86_REG_EAX, 1)
|
||||
|
||||
print(">>> Running emulation for the first time")
|
||||
mu.emu_start(address, address+1)
|
||||
mu.emu_start(address, address + 1)
|
||||
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
print(">>> EAX = 0x%x" %(mu.reg_read(UC_X86_REG_EAX)))
|
||||
print(">>> EAX = 0x%x" % (mu.reg_read(UC_X86_REG_EAX)))
|
||||
print(">>> Saving CPU context")
|
||||
saved_context = mu.context_save()
|
||||
|
||||
@ -457,9 +462,9 @@ def test_i386_context_save():
|
||||
pickled_saved_context = pickle.dumps(saved_context)
|
||||
|
||||
print(">>> Running emulation for the second time")
|
||||
mu.emu_start(address, address+1)
|
||||
mu.emu_start(address, address + 1)
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
print(">>> EAX = 0x%x" %(mu.reg_read(UC_X86_REG_EAX)))
|
||||
print(">>> EAX = 0x%x" % (mu.reg_read(UC_X86_REG_EAX)))
|
||||
|
||||
print(">>> Unpickling CPU context")
|
||||
saved_context = pickle.loads(pickled_saved_context)
|
||||
@ -469,11 +474,12 @@ def test_i386_context_save():
|
||||
|
||||
print(">>> CPU context restored. Below is the CPU context")
|
||||
mu.context_restore(saved_context)
|
||||
print(">>> EAX = 0x%x" %(mu.reg_read(UC_X86_REG_EAX)))
|
||||
print(">>> EAX = 0x%x" % (mu.reg_read(UC_X86_REG_EAX)))
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_x86_64():
|
||||
print("Emulate x86_64 code")
|
||||
try:
|
||||
@ -509,13 +515,13 @@ def test_x86_64():
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions in range [ADDRESS, ADDRESS+20]
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code64, None, ADDRESS, ADDRESS+20)
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code64, None, ADDRESS, ADDRESS + 20)
|
||||
|
||||
# tracing all memory READ & WRITE access
|
||||
mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_access)
|
||||
mu.hook_add(UC_HOOK_MEM_READ, hook_mem_access)
|
||||
# actually you can also use READ_WRITE to trace all memory access
|
||||
#mu.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, hook_mem_access)
|
||||
# mu.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, hook_mem_access)
|
||||
|
||||
try:
|
||||
# emulate machine code in infinite time
|
||||
@ -541,20 +547,20 @@ def test_x86_64():
|
||||
r14 = mu.reg_read(UC_X86_REG_R14)
|
||||
r15 = mu.reg_read(UC_X86_REG_R15)
|
||||
|
||||
print(">>> RAX = 0x%x" %rax)
|
||||
print(">>> RBX = 0x%x" %rbx)
|
||||
print(">>> RCX = 0x%x" %rcx)
|
||||
print(">>> RDX = 0x%x" %rdx)
|
||||
print(">>> RSI = 0x%x" %rsi)
|
||||
print(">>> RDI = 0x%x" %rdi)
|
||||
print(">>> R8 = 0x%x" %r8)
|
||||
print(">>> R9 = 0x%x" %r9)
|
||||
print(">>> R10 = 0x%x" %r10)
|
||||
print(">>> R11 = 0x%x" %r11)
|
||||
print(">>> R12 = 0x%x" %r12)
|
||||
print(">>> R13 = 0x%x" %r13)
|
||||
print(">>> R14 = 0x%x" %r14)
|
||||
print(">>> R15 = 0x%x" %r15)
|
||||
print(">>> RAX = 0x%x" % rax)
|
||||
print(">>> RBX = 0x%x" % rbx)
|
||||
print(">>> RCX = 0x%x" % rcx)
|
||||
print(">>> RDX = 0x%x" % rdx)
|
||||
print(">>> RSI = 0x%x" % rsi)
|
||||
print(">>> RDI = 0x%x" % rdi)
|
||||
print(">>> R8 = 0x%x" % r8)
|
||||
print(">>> R9 = 0x%x" % r9)
|
||||
print(">>> R10 = 0x%x" % r10)
|
||||
print(">>> R11 = 0x%x" % r11)
|
||||
print(">>> R12 = 0x%x" % r12)
|
||||
print(">>> R13 = 0x%x" % r13)
|
||||
print(">>> R14 = 0x%x" % r14)
|
||||
print(">>> R15 = 0x%x" % r15)
|
||||
|
||||
|
||||
except UcError as e:
|
||||
@ -626,19 +632,22 @@ def test_x86_16():
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
tmp = mu.mem_read(11, 1)
|
||||
print(">>> Read 1 bytes from [0x%x] = 0x%x" %(11, tmp[0]))
|
||||
print(">>> Read 1 bytes from [0x%x] = 0x%x" % (11, tmp[0]))
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def mmio_read_cb(uc, offset, size, data):
|
||||
print(f">>> Read IO memory at offset {hex(offset)} with {hex(size)} bytes and return 0x19260817")
|
||||
|
||||
return 0x19260817
|
||||
|
||||
|
||||
def mmio_write_cb(uc, offset, size, value, data):
|
||||
print(f">>> Write value {hex(value)} to IO memory at offset {hex(offset)} with {hex(size)} bytes")
|
||||
|
||||
|
||||
def test_i386_mmio():
|
||||
print("Test i386 IO memory")
|
||||
try:
|
||||
@ -664,6 +673,7 @@ def test_i386_mmio():
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_x86_16()
|
||||
test_i386()
|
Loading…
Reference in New Issue
Block a user