zyantific / zydis-rs Goto Github PK
View Code? Open in Web Editor NEWZydis Rust Bindings
License: MIT License
Zydis Rust Bindings
License: MIT License
hi! there is a bug in rust bindings(and potentially in zydis-c)
long short story
lea rax, [rsp+0x20]
DecodedOperand { id: 0, ty: REGISTER, visibility: EXPLICIT, **action: WRITE,** ... }
DecodedOperand { id: 1, ty: MEMORY, visibility: EXPLICIT, **action: (empty)**, ... }
lea eax, [esp+0x20]
DecodedOperand { id: 0, ty: REGISTER, visibility: EXPLICIT, **action: WRITE**, ... }
DecodedOperand { id: 1, ty: MEMORY, visibility: EXPLICIT, **action: (empty)**, ... }
code to reproduce bug
fn main() {
use zydis::*;
let data = [0x48, 0x8D, 0x44, 0x24, 0x20];
let decoder = Decoder::new(MachineMode::LONG_64, AddressWidth::_64).unwrap();
let instr = decoder.decode(&data).unwrap().unwrap();
let formatter = Formatter::new(FormatterStyle::INTEL).unwrap();
let mut buffer = [0u8; 200];
let mut buffer = OutputBuffer::new(&mut buffer[..]);
formatter
.format_instruction(&instr, &mut buffer, None, None)
.unwrap();
println!("{}", format!("{}", buffer));
for i in 0..instr.operand_count as usize {
println!("{:?}", instr.operands[i]);
}
println!();
let data = [0x8D, 0x44, 0x24, 0x20];
let decoder = Decoder::new(MachineMode::LONG_COMPAT_32, AddressWidth::_32).unwrap();
let instr = decoder.decode(&data).unwrap().unwrap();
let formatter = Formatter::new(FormatterStyle::INTEL).unwrap();
let mut buffer = [0u8; 200];
let mut buffer = OutputBuffer::new(&mut buffer[..]);
formatter
.format_instruction(&instr, &mut buffer, None, None)
.unwrap();
println!("{}", format!("{}", buffer));
for i in 0..instr.operand_count as usize {
println!("{:?}", instr.operands[i]);
}
}
The InstructionAttributes
bitflag constant IS_PRIVILIGED
is misspelled; it should be IS_PRIVILIGED
:
Line 750 in 1a77840
In the C source, the documentation is misspelled, but the symbol name is correctly spelled: https://github.com/zyantific/zydis/blob/356e0e60c1e7e3c9a7002e3ea9b9c6e95de9ca8c/include/Zydis/DecoderTypes.h#L265
Hi, i've noticed some strange stuff. When printing with dbg!()
macro i noticed that some AccessedFlags
looks weird. They are always wrapped in an Option
enum, even though when working with my binary it was always evaluating to Some
. Also, in many places we can see the 0x0
instead of something like UNUSED
. I think that AccessedFlags
probably should not be wrapped inside an Option
enum, but instead it's fields should be.
Here is an example:
add r9b, 0xA9
[src/deep_taint_run.rs:76] insn.cpu_flags = Some(
AccessedFlags {
tested: CpuFlag(
0x0,
),
modified: CpuFlag(
CF | PF | AF | ZF | SF | OF,
),
set_0: CpuFlag(
0x0,
),
set_1: CpuFlag(
0x0,
),
undefined: CpuFlag(
0x0,
),
},
)
P.s. Idk honestly how to process all this flags btw. (i.e. log reads/writes to specific flags, etc)
Take a look at this example:
use zydis::{self, Decoder, FullInstruction, InstructionAttributes};
fn main() {
let push_rax = [0x50];
// Btw i get a hint to include zydis::ffi::Decoder.
// I dont think we need it. Need to check visibility of some funcs
let decoder = Decoder::new64();
let decoded: FullInstruction = decoder.decode_first(&push_rax).unwrap().unwrap();
dbg!(decoded.operands());
dbg!(decoded.attributes);
assert!(decoded.attributes.contains(InstructionAttributes::HAS_SEGMENT_SS));
// Also idk how decoded.segments() work
// Offtop: I need a hint on how to detect conditional branches and conditional reads/writes
}
[src/main.rs:11] decoded.operands() = [
DecodedOperand {
id: 0,
visibility: EXPLICIT,
action: OperandAction(
READ,
),
encoding: OPCODE,
size: 64,
element_type: INT,
element_size: 64,
element_count: 1,
attributes: OperandAttributes(
0x0,
),
kind: Reg(
RAX,
),
},
DecodedOperand {
id: 1,
visibility: HIDDEN,
action: OperandAction(
READ | WRITE,
),
encoding: NONE,
size: 64,
element_type: INT,
element_size: 64,
element_count: 1,
attributes: OperandAttributes(
0x0,
),
kind: Reg(
RSP,
),
},
DecodedOperand {
id: 2,
visibility: HIDDEN,
action: OperandAction(
WRITE,
),
encoding: NONE,
size: 64,
element_type: INT,
element_size: 64,
element_count: 1,
attributes: OperandAttributes(
0x0,
),
kind: Mem(
MemoryInfo {
ty: MEM,
segment: SS,
base: RSP,
index: NONE,
scale: 0,
disp: DisplacementInfo {
has_displacement: false,
displacement: 0,
},
},
),
},
]
[src/main.rs:12] decoded.attributes = InstructionAttributes(
0x0,
)
thread 'main' panicked at src/main.rs:13:5:
assertion failed: decoded.attributes.contains(InstructionAttributes::HAS_SEGMENT_SS)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
As we can see, the InstructionAttributes is nonexistent and also lacks some pretty representation. I have tested it with lots of instructions and the issue is present in all of them.
I believe that zydis-rs may crash in some cases when serializing instructions, either via serde_json or via debug format (println!("{:?}", insn)
). This seems to be due to some operands being invalid. Without doing any research, I wonder if the underlying zydis library does not initialize the unused operands resulting in the serializer getting confused by unexpected enum values or something.
Short term fix: When I overwrite the operands from insn.operand_count..10
with a dummy zero operand, then serialization (edit: sometimes) works:
I apologize for not having a test case ready. Would you like me to provide one?
zydis-rs fails to build when the serialization
feature is enabled due to a cfg_attr
being misspelled:
Line 728 in 1a77840
If you try using this library directly in a Windows kernel driveryou'll see five extra imports from Kernel32.dll that shouldn't be there.
If you look at the Visual Studio solutions in zydis/msvc, you'll see that the ZydisWinKernel solution needs the BufferOverflowK library to build properly.
This can be fixed adding the following line to build.rs
:
println!("cargo:rustc-link-lib=BufferOverflowK");
I've encountered the following bug with zydis rust bindings v 3.1.3:
Running the following:
println!("{:?}", zydis::Register::FLAGS.get_largest_enclosing(zydis::MachineMode::LONG_64));
Ouputs this:
None
while in fact, i expect to see the RFLAGS as a result
Hello all,
Is there any plan to support zydis v2-beta
? I pulled the master
branch for zydis-c
, but zydis-rs
doesn't compile. I have tried to fix it myself but it is beyond my current knowledge about Rust :(
Using the basic example shown in the readme on linux, zydis-rs builds and links just fine (with dependecy zydis = { git = "https://github.com/zyantific/zydis-rs"}
):
However, on Windows/Visual Studio, the example fails:
I believe this is because on Windows, cmake builds the zydis-c static libraries in a subdirectory named after CMAKE_BUILD_TYPE
, eg. Build
. On linux, the static libraries are placed into the root build directory.
See this is the build root, and Zycore.lib
is not found:
but is placed in ./Debug/
:
and likewise for Zydis.lib
.
As I'm still fairly new to rust and not familiar with the cmake
crate, I'm not sure if this is common behavior. I'll make an attempt to update build.rs
to autodetect Windows/Visual Studio and fix the build path; though, you may have better ideas for a fix.
When cross compiling for armv7/aarch64 a crate that depends on zydis-rs, the compilation fails with a mismatched types
error:
error[E0308]: mismatched types
--> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/zydis-3.1.1/src/ffi.rs:202:17
|
202 | buffer as *mut i8,
| ^^^^^^^^^^^^^^^^^ expected `u8`, found `i8`
|
= note: expected raw pointer `*mut u8`
found raw pointer `*mut i8`
error[E0308]: mismatched types
--> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/zydis-3.1.1/src/ffi.rs:245:17
|
245 | buffer.as_ptr() as *const i8,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `i8`
|
= note: expected raw pointer `*const u8`
found raw pointer `*const i8`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
error: could not compile `zydis` due to 3 previous errors
warning: build failed, waiting for other jobs to finish...
error: build failed
https://github.com/williballenthin/lancelot/runs/4215259537?check_suite_focus=true
Line 202 is
Lines 200 to 204 in 2089243
We see the buffer
parameters to ZyanStringInitCustomBuffer
should be a *mut c_char
:
Lines 1143 to 1147 in 2089243
and the buffer above is casted to a *mut i8
. This is correct on x64 but not arm:
I think this can be fixed on lines 202 and 245 with a change like here:
https://github.com/jeaye/ncurses-rs/pull/100/files
Hi,
I am trying to build a project with Zydis-rs. I am following the README and setting
[dependencies]
zydis = "0.0.4"
When I run cargo build
I get the following error:
$ cargo build
Updating registry `https://github.com/rust-lang/crates.io-index`
error: no matching version `^0.0.4` found for package `zydis`
location searched: registry `https://github.com/rust-lang/crates.io-index`
versions found: 0.0.3, 0.0.1
required by package `nopstats v0.1.0 ({file path})`
Could the new version be pushed to crates.io?
Thanks
Alex
Are there any plans on updating these bindings to the latest Zydis version with encoder support?
I believe there is probably a UB bug in the handling of userdata pointers passed from Formatter.format_instruction
to formatter callbacks. This results in segfaults and unexpected unwrap failures in non-unsafe client code. So far, I've only been able to trigger this issue when optimizations and LTO are enabled.
The example repo https://github.com/williballenthin/zydis-rs-issue-29 contains minimal programs that demonstrate the issue. The issue is present when built in release mode (which has fat LTO enabled) but not in debug mode.
b.rs
is the more minimal example and completely non-unsafe. Although Some(...)
is passed to format_instruction
, the formatter callback receives None
as the userdata:
a.rs
more closely represents the code in another project that led to this bug discovery. There's a bit more data provided in the userdata structure, and rather than receiving None
, the callback ends up with some unexpected data and segfaults. (Note: there is a single line of unsafe
in this binary; however, I believe its unrelated, as I think its a well defined and valid cast across Formatter representations.)
I suspect the behaviors shown by a.rs
and b.rs
both stem from the same bug.
Notably, these test cases only demonstrate the issue when fat LTO is enabled (see release profile in Cargo.toml
). However, I'm not exactly sure what this means. Suspicions include:
&mut dyn Any
and back is not well defined, orGiven that LTO is fairly widely used and tested, I think (1) or similar is more likely than (2). Unfortunately, I have pretty much avoided unsafe
Rust because I don't know the safety rules well enough, so I don't know how to triage further.
Does zydis-rs already support one of the wasm targets? If not, what is the outlook for this?
I'll admit, I haven't researched this too thoroughly, so maybe the answer is obvious already. In any case, I'd like to express that I'm interested in using zydis-rs in a wasm project (probably some sort of binary analysis that runs in the browser). Therefore, if this has already been considered (and done?), then sample code or pointers to getting this working are appreciated.
It would nice to get the ZYDIS_ATTRIB_IS_FAR_BRANCH flag
I'd like to inspect the mnemonic of decoded instructions in order to find specific instructions. This is not as easy as I'd like because of a type mismatch between the mnemonic constants and the mnemonic field.
A ZydisDecodedInstruction_
has a field mnemonic
with type ZydisMnemonic
:
ZydisMnemonic
is an alias for u16
:
The mnemonic constants exported have type ZydisMnemonics
:
And, unfortunately, ZydisMnemonics
is an alias for c_uint
:
This prevents me from directly comparing the mnemonic field of a decoded instruction to a constant exported by Zydis:
Would you consider changing the type of ZydisMnemonic
or ZydisMnemonics
so that they are the same?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.