Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust bindings improvements #1480

Merged
merged 12 commits into from Nov 10, 2021
Merged

Rust bindings improvements #1480

merged 12 commits into from Nov 10, 2021

Conversation

domenukk
Copy link
Contributor

@domenukk domenukk commented Nov 8, 2021

These bindings from unicornafl allow us to

  • use a data ptr (if this one is needed is debatable, what do you think?)
  • have closure that don't live for'static anymore -> easier to capture things in
  • have non-boxed closures (perf++, hopefully)
  • no_std (potentially smaller)
  • no longer need to cast regs to i32 manually

uc.c Outdated Show resolved Hide resolved
bindings/rust/src/lib.rs Outdated Show resolved Hide resolved
@domenukk
Copy link
Contributor Author

@wtdcode got rid of the additional API

@wtdcode wtdcode merged commit fafec70 into unicorn-engine:dev Nov 10, 2021
@wtdcode
Copy link
Member

wtdcode commented Nov 10, 2021

Merged, thanks. ;)

@domenukk
Copy link
Contributor Author

@wtdcode one thing, in case you autogenerate the register ids, make sure you add

impl From<RegisterARM> for i32 {
    fn from(r: RegisterARM) -> Self {
        r as i32
    }
}

to each file :)

@wtdcode
Copy link
Member

wtdcode commented Nov 10, 2021

@wtdcode one thing, in case you autogenerate the register ids, make sure you add

impl From<RegisterARM> for i32 {
    fn from(r: RegisterARM) -> Self {
        r as i32
    }
}

to each file :)

Rust bindings constants are not generated automatically unfortunately and that's on my TODO plan.

@bet4it
Copy link
Contributor

bet4it commented Nov 10, 2021

There are two types of mem callback:

/*
Callback function for hooking memory (READ, WRITE & FETCH)
@type: this memory is being READ, or WRITE
@address: address where the code is being executed
@size: size of data being read or written
@value: value of data being written to memory, or irrelevant if type = READ.
@user_data: user data passed to tracing APIs
*/
typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,
uint64_t address, int size, int64_t value, void *user_data);
/*
Callback function for handling invalid memory access events (UNMAPPED and
PROT events)
@type: this memory is being READ, or WRITE
@address: address where the code is being executed
@size: size of data being read or written
@value: value of data being written to memory, or irrelevant if type = READ.
@user_data: user data passed to tracing APIs
@return: return true to continue, or false to stop program (due to invalid memory).
NOTE: returning true to continue execution will only work if the accessed
memory is made accessible with the correct permissions during the hook.
In the event of a UC_MEM_READ_UNMAPPED or UC_MEM_WRITE_UNMAPPED callback,
the memory should be uc_mem_map()-ed with the correct permissions, and the
instruction will then read or write to the address as it was supposed to.
In the event of a UC_MEM_FETCH_UNMAPPED callback, the memory can be mapped
in as executable, in which case execution will resume from the fetched address.
The instruction pointer may be written to in order to change where execution resumes,
but the fetch must succeed if execution is to resume.
*/
typedef bool (*uc_cb_eventmem_t)(uc_engine *uc, uc_mem_type type,
uint64_t address, int size, int64_t value, void *user_data);

uc_cb_eventmem_t has a return value but uc_cb_hookmem_t doesn't.
You may need to add a new add_mem_invalid_hook function.

uc_cb_hookinsn_invalid_t and uc_cb_insn_in_t also have a return value:

/*
Callback function for tracing invalid instructions
@user_data: user data passed to tracing APIs.
@return: return true to continue, or false to stop program (due to invalid instruction).
*/
typedef bool (*uc_cb_hookinsn_invalid_t)(uc_engine *uc, void *user_data);
/*
Callback function for tracing IN instruction of X86
@port: port number
@size: data size (1/2/4) to be read from this port
@user_data: user data passed to tracing APIs.
*/
typedef uint32_t (*uc_cb_insn_in_t)(uc_engine *uc, uint32_t port, int size, void *user_data);

You may change them in this PR.

Originally posted by @bet4it in #1421 (comment)

mem_hook_proxy shouldn't always return a bool.

@domenukk
Copy link
Contributor Author

@wtdcode one thing, in case you autogenerate the register ids, make sure you add

impl From<RegisterARM> for i32 {
    fn from(r: RegisterARM) -> Self {
        r as i32
    }
}

to each file :)

Rust bindings constants are not generated automatically unfortunately and that's on my TODO plan.

I had it running at one point, but probably needs some adaption to newer changes, take a look at:
https://github.com/AFLplusplus/unicornafl/blob/6c9ed25bfb8ff8650921fc27be74ba4e6b7282a4/bindings/const_generator.py

@domenukk
Copy link
Contributor Author

There are two types of mem callback:

/*
Callback function for hooking memory (READ, WRITE & FETCH)
@type: this memory is being READ, or WRITE
@address: address where the code is being executed
@size: size of data being read or written
@value: value of data being written to memory, or irrelevant if type = READ.
@user_data: user data passed to tracing APIs
*/
typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,
uint64_t address, int size, int64_t value, void *user_data);
/*
Callback function for handling invalid memory access events (UNMAPPED and
PROT events)
@type: this memory is being READ, or WRITE
@address: address where the code is being executed
@size: size of data being read or written
@value: value of data being written to memory, or irrelevant if type = READ.
@user_data: user data passed to tracing APIs
@return: return true to continue, or false to stop program (due to invalid memory).
NOTE: returning true to continue execution will only work if the accessed
memory is made accessible with the correct permissions during the hook.
In the event of a UC_MEM_READ_UNMAPPED or UC_MEM_WRITE_UNMAPPED callback,
the memory should be uc_mem_map()-ed with the correct permissions, and the
instruction will then read or write to the address as it was supposed to.
In the event of a UC_MEM_FETCH_UNMAPPED callback, the memory can be mapped
in as executable, in which case execution will resume from the fetched address.
The instruction pointer may be written to in order to change where execution resumes,
but the fetch must succeed if execution is to resume.
*/
typedef bool (*uc_cb_eventmem_t)(uc_engine *uc, uc_mem_type type,
uint64_t address, int size, int64_t value, void *user_data);

uc_cb_eventmem_t has a return value but uc_cb_hookmem_t doesn't.
You may need to add a new add_mem_invalid_hook function.

uc_cb_hookinsn_invalid_t and uc_cb_insn_in_t also have a return value:

/*
Callback function for tracing invalid instructions
@user_data: user data passed to tracing APIs.
@return: return true to continue, or false to stop program (due to invalid instruction).
*/
typedef bool (*uc_cb_hookinsn_invalid_t)(uc_engine *uc, void *user_data);
/*
Callback function for tracing IN instruction of X86
@port: port number
@size: data size (1/2/4) to be read from this port
@user_data: user data passed to tracing APIs.
*/
typedef uint32_t (*uc_cb_insn_in_t)(uc_engine *uc, uint32_t port, int size, void *user_data);

You may change them in this PR.

Originally posted by @bet4it in #1421 (comment)

mem_hook_proxy shouldn't always return a bool.

Ah, missed that. Will take a look at it later and open another pr (unless someone else wants to)

@domenukk
Copy link
Contributor Author

@bet4it what do you recommend? Drop the bool return again? Add a hook?

@bet4it
Copy link
Contributor

bet4it commented Nov 11, 2021

Add add_mem_invalid_hook and add_insn_in_invalid_hook function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants