put pyo3 away for now

This commit is contained in:
Jean-Marie Mineau 2025-01-24 16:43:30 +01:00
parent ea6ce5d7a1
commit 1c45b9e38b
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
15 changed files with 248 additions and 215 deletions

View file

@ -14,8 +14,8 @@ androscalpel_serializer = { version = "0.1.0", path = "../androscalpel_serialize
anyhow = { version = "1.0.75", features = ["backtrace"] } anyhow = { version = "1.0.75", features = ["backtrace"] }
apk_frauder = { version = "0.1.0", path = "../apk_frauder" } apk_frauder = { version = "0.1.0", path = "../apk_frauder" }
log = "0.4.20" log = "0.4.20"
pyo3 = { version = "0.23.4", features = ["anyhow", "abi3-py38"] } pyo3 = { version = "0.23.4", features = ["anyhow", "abi3-py38", "extension-module"], optional = true}
pyo3-log = "0.12.1" pyo3-log = { version = "0.12.1", optional = true}
rayon = "1.9.0" rayon = "1.9.0"
serde = { version = "1.0.195", features = ["derive"] } serde = { version = "1.0.195", features = ["derive"] }
serde_json = "1.0.111" serde_json = "1.0.111"
@ -24,6 +24,7 @@ sha1 = "0.10.6"
[dev-dependencies] [dev-dependencies]
pretty_assertions = "1.4.1" pretty_assertions = "1.4.1"
#[features] [features]
#extension-module = ["pyo3/extension-module"] default = []
#default = [""] # TODO: need refactoring to https://github.com/PyO3/pyo3/issues/2935#issuecomment-2560930677 or cfg_eval https://github.com/rust-lang/rust/issues/82679
python = ["pyo3", "pyo3-log"]

View file

@ -2,6 +2,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
#[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::hashmap_vectorize; use crate::hashmap_vectorize;
@ -11,28 +12,28 @@ use crate::{
}; };
/// Annotation with a visibility /// Annotation with a visibility
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct DexAnnotationItem { pub struct DexAnnotationItem {
// TODO: the get/set will probably be wonky on the python side when edditing // TODO: the get/set will probably be wonky on the python side when edditing
/// The actual annotation /// The actual annotation
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub annotation: DexAnnotation, pub annotation: DexAnnotation,
// TODO: enforce exclusivity // TODO: enforce exclusivity
/// If the annotation visibility is set to build /// If the annotation visibility is set to build
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub visibility_build: bool, pub visibility_build: bool,
/// If the annotation visibility is set to runtime /// If the annotation visibility is set to runtime
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub visibility_runtime: bool, pub visibility_runtime: bool,
/// If the annotation visibility is set to system /// If the annotation visibility is set to system
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub visibility_system: bool, pub visibility_system: bool,
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl DexAnnotationItem { impl DexAnnotationItem {
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(annotation: DexAnnotation) -> Self { pub fn new(annotation: DexAnnotation) -> Self {
Self { Self {
annotation, annotation,
@ -101,7 +102,7 @@ impl DexAnnotationItem {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
@ -122,23 +123,23 @@ impl<V: VisitorMut> VisitableMut<V> for DexAnnotationItem {
} }
/// An annotation. /// An annotation.
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct DexAnnotation { pub struct DexAnnotation {
// TODO: check the relation between type and encoded_value. // TODO: check the relation between type and encoded_value.
/// The type of the annotation. /// The type of the annotation.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub type_: IdType, pub type_: IdType,
// TODO: the get/set will probably be wonky on the python side when edditing // TODO: the get/set will probably be wonky on the python side when edditing
/// The annotation elements. /// The annotation elements.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
#[serde(with = "hashmap_vectorize")] #[serde(with = "hashmap_vectorize")]
pub elements: HashMap<DexString, DexValue>, // TODO: check MemberName syntax? pub elements: HashMap<DexString, DexValue>, // TODO: check MemberName syntax?
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl DexAnnotation { impl DexAnnotation {
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(type_: IdType, elements: HashMap<DexString, DexValue>) -> Self { pub fn new(type_: IdType, elements: HashMap<DexString, DexValue>) -> Self {
Self { type_, elements } Self { type_, elements }
} }
@ -218,7 +219,7 @@ impl DexAnnotation {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }

View file

@ -8,8 +8,8 @@ use std::io::Cursor;
use std::path::PathBuf; use std::path::PathBuf;
use log::info; use log::info;
use pyo3::prelude::*; #[cfg(feature = "python")]
use pyo3::types::PyBytes; use pyo3::{prelude::*, types::PyBytes};
use crate::ins::CallSite; use crate::ins::CallSite;
use crate::instructions; use crate::instructions;
@ -32,7 +32,7 @@ pub struct DexFile {
} }
/// Represent an apk. /// Represent an apk.
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)] #[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
pub struct Apk { pub struct Apk {
pub dex_files: HashMap<String, DexFile>, // TODO: use accessort for chache invalidation pub dex_files: HashMap<String, DexFile>, // TODO: use accessort for chache invalidation
@ -2981,9 +2981,9 @@ impl Apk {
} }
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl Apk { impl Apk {
#[new] #[cfg_attr(feature = "python", new)]
pub fn new() -> Self { pub fn new() -> Self {
// TODO take argument and dispatch to load_apk or load_apk_bin // TODO take argument and dispatch to load_apk or load_apk_bin
Self { Self {
@ -2993,8 +2993,8 @@ impl Apk {
/// Load all android files in an application. /// Load all android files in an application.
/// This **does not include any .dex file that android would not load. /// This **does not include any .dex file that android would not load.
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
#[pyo3(signature = (apk, label_each_ins=false, cache=false))] #[cfg_attr(feature = "python", pyo3(signature = (apk, label_each_ins=false, cache=false)))]
pub fn load_apk(apk: PathBuf, label_each_ins: bool, cache: bool) -> Result<Self> { pub fn load_apk(apk: PathBuf, label_each_ins: bool, cache: bool) -> Result<Self> {
let file = File::open(apk)?; let file = File::open(apk)?;
let mut apk_z = ZipFileReader::new(file); let mut apk_z = ZipFileReader::new(file);
@ -3013,8 +3013,8 @@ impl Apk {
/// Load all android files in an application. /// Load all android files in an application.
/// This **does not include any .dex file that android would not load. /// This **does not include any .dex file that android would not load.
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
#[pyo3(signature = (apk, label_each_ins=false, cache=false))] #[cfg_attr(feature = "python", pyo3(signature = (apk, label_each_ins=false, cache=false)))]
pub fn load_apk_bin(apk: &[u8], label_each_ins: bool, cache: bool) -> Result<Self> { pub fn load_apk_bin(apk: &[u8], label_each_ins: bool, cache: bool) -> Result<Self> {
let mut apk_z = ZipFileReader::new(Cursor::new(apk)); let mut apk_z = ZipFileReader::new(Cursor::new(apk));
let mut apk = Self::default(); let mut apk = Self::default();
@ -3039,7 +3039,7 @@ impl Apk {
/// - `label_each_ins`: if set to true, insert a label before each instruction /// - `label_each_ins`: if set to true, insert a label before each instruction
/// indicating the instruction address /// indicating the instruction address
/// - `cache`: if set to true, copy and cache the binary data format. /// - `cache`: if set to true, copy and cache the binary data format.
#[pyo3(signature = (name, data, label_each_ins=false, cache=false))] #[cfg_attr(feature = "python", pyo3(signature = (name, data, label_each_ins=false, cache=false)))]
pub fn add_dex_file( pub fn add_dex_file(
&mut self, &mut self,
name: &str, name: &str,
@ -3096,7 +3096,7 @@ impl Apk {
Ok(()) Ok(())
} }
#[pyo3(signature = (method_id, code=None, dex_file=None))] #[cfg_attr(feature = "python", pyo3(signature = (method_id, code=None, dex_file=None)))]
pub fn set_method_code( pub fn set_method_code(
&mut self, &mut self,
method_id: IdMethod, method_id: IdMethod,
@ -3131,6 +3131,7 @@ impl Apk {
Ok(()) Ok(())
} }
#[cfg(feature = "python")]
#[pyo3(name = "gen_raw_dex")] //Sad GIL noise #[pyo3(name = "gen_raw_dex")] //Sad GIL noise
pub fn py_gen_raw_dex(&self, py: Python<'_>) -> Result<HashMap<String, PyObject>> { pub fn py_gen_raw_dex(&self, py: Python<'_>) -> Result<HashMap<String, PyObject>> {
Ok(self Ok(self
@ -3144,12 +3145,12 @@ impl Apk {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[pyo3(signature = (class, dex_file=None))] #[cfg_attr(feature = "python", pyo3(signature = (class, dex_file=None)))]
pub fn remove_class(&mut self, class: &IdType, dex_file: Option<&str>) -> Result<()> { pub fn remove_class(&mut self, class: &IdType, dex_file: Option<&str>) -> Result<()> {
if let Some(dex_file) = dex_file { if let Some(dex_file) = dex_file {
self.dex_files self.dex_files

View file

@ -3,6 +3,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
#[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{ use crate::{
@ -12,80 +13,80 @@ use crate::{
use androscalpel_serializer::consts::*; use androscalpel_serializer::consts::*;
/// Represent an apk /// Represent an apk
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Class { pub struct Class {
/// Type, format described at /// Type, format described at
/// <https://source.android.com/docs/core/runtime/dex-format#typedescriptor> /// <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub descriptor: IdType, pub descriptor: IdType,
/// If the class is visible everywhere /// If the class is visible everywhere
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_public: bool, pub is_public: bool,
/// If the class is subclassable /// If the class is subclassable
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_final: bool, pub is_final: bool,
/// If the class is a 'multipy-implementable abstract class' AKA an interface /// If the class is a 'multipy-implementable abstract class' AKA an interface
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_interface: bool, pub is_interface: bool,
/// If the class is instanciable /// If the class is instanciable
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_abstract: bool, pub is_abstract: bool,
/// If the class is not directly defined in the source code /// If the class is not directly defined in the source code
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_synthetic: bool, pub is_synthetic: bool,
/// If the class is an annotation /// If the class is an annotation
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_annotation: bool, pub is_annotation: bool,
/// If the class is an enum /// If the class is an enum
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_enum: bool, pub is_enum: bool,
/// Name of the superclass, format described at /// Name of the superclass, format described at
/// <https://source.android.com/docs/core/runtime/dex-format#typedescriptor> /// <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub superclass: Option<IdType>, pub superclass: Option<IdType>,
/// List of the interfaces that class implement, format of the interfaces /// List of the interfaces that class implement, format of the interfaces
/// name is discribed at /// name is discribed at
/// <https://source.android.com/docs/core/runtime/dex-format#typedescriptor> /// <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub interfaces: Vec<IdType>, pub interfaces: Vec<IdType>,
/// Name of the source file where this class is defined. /// Name of the source file where this class is defined.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub source_file: Option<DexString>, pub source_file: Option<DexString>,
/// The static fields /// The static fields
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub static_fields: HashMap<IdField, Field>, pub static_fields: HashMap<IdField, Field>,
/// The instance fields /// The instance fields
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub instance_fields: HashMap<IdField, Field>, pub instance_fields: HashMap<IdField, Field>,
/// The direct (static, private or constructor) methods of the class /// The direct (static, private or constructor) methods of the class
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub direct_methods: HashMap<IdMethod, Method>, pub direct_methods: HashMap<IdMethod, Method>,
/// The virtual (ie non direct) methods of the class /// The virtual (ie non direct) methods of the class
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub virtual_methods: HashMap<IdMethod, Method>, pub virtual_methods: HashMap<IdMethod, Method>,
// Do we need to distinguish direct and virtual (all the other) methods? // Do we need to distinguish direct and virtual (all the other) methods?
// Maybe overlapping descriptor (same name, class and proto?) // Maybe overlapping descriptor (same name, class and proto?)
/// The annotation related to this class (note: this does not include the /// The annotation related to this class (note: this does not include the
/// methods/field/parameters annotations, they are stored in the methods and fields /// methods/field/parameters annotations, they are stored in the methods and fields
/// structutres) /// structutres)
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub annotations: Vec<DexAnnotationItem>, pub annotations: Vec<DexAnnotationItem>,
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl Class { impl Class {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(name: DexString) -> Result<Self> { pub fn new(name: DexString) -> Result<Self> {
Ok(Self { Ok(Self {
descriptor: IdType::new(name)?, descriptor: IdType::new(name)?,

View file

@ -4,6 +4,7 @@ use anyhow::anyhow;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
#[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{ use crate::{
@ -16,26 +17,26 @@ use crate::{
// type TmpHandlerType = (Vec<(IdType, u32)>, Option<u32>); // type TmpHandlerType = (Vec<(IdType, u32)>, Option<u32>);
/// The code run by a method. /// The code run by a method.
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Code { pub struct Code {
// TODO: remove and compute this value from code? // TODO: remove and compute this value from code?
/// The number of registers used by the code /// The number of registers used by the code
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub registers_size: u16, pub registers_size: u16,
// TODO: what does it means? is it computable? // TODO: what does it means? is it computable?
/// The number of words of incoming arguments to the method /// The number of words of incoming arguments to the method
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub ins_size: u16, pub ins_size: u16,
// TODO: what does it means? is it computable? // TODO: what does it means? is it computable?
/// The number of words of outgoing argument space /// The number of words of outgoing argument space
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub outs_size: u16, pub outs_size: u16,
/// The names of the parameters if given /// The names of the parameters if given
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub parameter_names: Option<Vec<Option<DexString>>>, pub parameter_names: Option<Vec<Option<DexString>>>,
/// The instructions. /// The instructions.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub insns: Vec<Instruction>, pub insns: Vec<Instruction>,
} }
@ -51,19 +52,19 @@ impl PartialEq for Code {
} }
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl Code { impl Code {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
#[pyo3(signature = (registers_size, ins_size, outs_size, insns, parameter_names=None))] #[cfg_attr(feature = "python", pyo3(signature = (registers_size, ins_size, outs_size, insns, parameter_names=None)))]
pub fn new( pub fn new(
registers_size: u16, registers_size: u16,
ins_size: u16, ins_size: u16,

View file

@ -6,6 +6,7 @@ use std::collections::HashSet;
use std::hash::Hash; use std::hash::Hash;
use anyhow::{anyhow, bail, Context}; use anyhow::{anyhow, bail, Context};
#[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{scalar::*, DexString, DexValue, Result, Visitable, VisitableMut, Visitor, VisitorMut}; use crate::{scalar::*, DexString, DexValue, Result, Visitable, VisitableMut, Visitor, VisitorMut};
@ -13,7 +14,7 @@ use androscalpel_serializer::{StringDataItem, Uleb128};
/// The type of a method. The shorty is formated as described in /// The type of a method. The shorty is formated as described in
/// <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor> /// <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
#[pyclass(eq, ord, hash, frozen)] #[cfg_attr(feature = "python", pyclass(eq, ord, hash, frozen))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct IdMethodType { pub struct IdMethodType {
/// Type formated as described by <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor> /// Type formated as described by <https://source.android.com/docs/core/runtime/dex-format#shortydescriptor>
@ -62,18 +63,18 @@ impl PartialOrd for IdMethodType {
} }
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl IdMethodType { impl IdMethodType {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(return_type: IdType, parameters: Vec<IdType>) -> Self { pub fn new(return_type: IdType, parameters: Vec<IdType>) -> Self {
Self { Self {
shorty: Self::compute_shorty(&return_type, &parameters), shorty: Self::compute_shorty(&return_type, &parameters),
@ -100,7 +101,7 @@ impl IdMethodType {
/// ) /// )
/// ); /// );
/// ``` /// ```
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_smali(smali_repr: &str) -> Result<Self> { pub fn from_smali(smali_repr: &str) -> Result<Self> {
if smali_repr.len() < 2 { if smali_repr.len() < 2 {
bail!("'{smali_repr}' is to short to be a prototype"); bail!("'{smali_repr}' is to short to be a prototype");
@ -229,7 +230,7 @@ impl IdMethodType {
/// as described here <https://source.android.com/docs/core/runtime/dex-format#typedescriptor> /// as described here <https://source.android.com/docs/core/runtime/dex-format#typedescriptor>
// Not a clean rust enum because we want to be compatible with python, and maybe support strange // Not a clean rust enum because we want to be compatible with python, and maybe support strange
// malware edge case? // malware edge case?
#[pyclass(eq, ord, hash, frozen)] #[cfg_attr(feature = "python", pyclass(eq, ord, hash, frozen))]
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct IdType(pub(crate) DexString); pub struct IdType(pub(crate) DexString);
@ -244,20 +245,24 @@ impl<V: VisitorMut> VisitableMut<V> for IdType {
Ok(Self(v.visit_string(self.0)?)) Ok(Self(v.visit_string(self.0)?))
} }
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl IdType { impl IdType {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new( pub fn new(
#[pyo3(from_py_with = "crate::dex_string::as_dex_string")] ty: DexString, #[cfg_attr(
feature = "python",
pyo3(from_py_with = "crate::dex_string::as_dex_string")
)]
ty: DexString,
) -> Result<Self> { ) -> Result<Self> {
// TODO: check format // TODO: check format
let ty = Self(ty); let ty = Self(ty);
@ -266,7 +271,7 @@ impl IdType {
} }
/// Return a type from its string representation without checking its format /// Return a type from its string representation without checking its format
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn unchecked_new(ty: DexString) -> Self { pub fn unchecked_new(ty: DexString) -> Self {
Self(ty) Self(ty)
} }
@ -288,7 +293,7 @@ impl IdType {
/// IdType::class("androidx/core/util/Predicate") /// IdType::class("androidx/core/util/Predicate")
/// ); /// );
/// ``` /// ```
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_smali(smali_repr: &str) -> Result<Self> { pub fn from_smali(smali_repr: &str) -> Result<Self> {
Self::new(smali_repr.into()) Self::new(smali_repr.into())
} }
@ -310,7 +315,7 @@ impl IdType {
/// IdType::boolean(), /// IdType::boolean(),
/// ]) /// ])
/// ``` /// ```
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn get_list_from_str(type_list: &str) -> Result<Vec<Self>> { pub fn get_list_from_str(type_list: &str) -> Result<Vec<Self>> {
let mut lst = vec![]; let mut lst = vec![];
let mut chars = type_list.chars(); let mut chars = type_list.chars();
@ -364,66 +369,66 @@ impl IdType {
} }
/// Return the void type (for return type) /// Return the void type (for return type)
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn void() -> Self { pub fn void() -> Self {
Self("V".into()) Self("V".into())
} }
/// Return the boolean type /// Return the boolean type
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn boolean() -> Self { pub fn boolean() -> Self {
Self("Z".into()) Self("Z".into())
} }
/// Return the byte type /// Return the byte type
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn byte() -> Self { pub fn byte() -> Self {
Self("B".into()) Self("B".into())
} }
/// Return the short type /// Return the short type
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn short() -> Self { pub fn short() -> Self {
Self("S".into()) Self("S".into())
} }
/// Return the char type /// Return the char type
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn char() -> Self { pub fn char() -> Self {
Self("C".into()) Self("C".into())
} }
/// Return the int type /// Return the int type
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn int() -> Self { pub fn int() -> Self {
Self("I".into()) Self("I".into())
} }
/// Return the long type /// Return the long type
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn long() -> Self { pub fn long() -> Self {
Self("J".into()) Self("J".into())
} }
/// Return the float type /// Return the float type
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn float() -> Self { pub fn float() -> Self {
Self("F".into()) Self("F".into())
} }
/// Return the double type /// Return the double type
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn double() -> Self { pub fn double() -> Self {
Self("D".into()) Self("D".into())
} }
/// Return the type for the class of fully qualified name `name` /// Return the type for the class of fully qualified name `name`
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn class(name: &str) -> Self { pub fn class(name: &str) -> Self {
Self(format!("L{name};").into()) Self(format!("L{name};").into())
} }
/// Return the type for an array of the specify `type_` /// Return the type for an array of the specify `type_`
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn array(type_: &IdType) -> Self { pub fn array(type_: &IdType) -> Self {
let mut ty = type_.clone(); let mut ty = type_.clone();
ty.0 .0.utf16_size.0 += 1; ty.0 .0.utf16_size.0 += 1;
@ -636,18 +641,18 @@ impl SmaliName for IdType {
} }
} }
#[pyclass(eq, ord, hash, frozen)] #[cfg_attr(feature = "python", pyclass(eq, ord, hash, frozen))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct IdField { pub struct IdField {
/// The name of the field, format described at /// The name of the field, format described at
/// <https://source.android.com/docs/core/runtime/dex-format#membername> /// <https://source.android.com/docs/core/runtime/dex-format#membername>
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub name: DexString, pub name: DexString,
/// The type of the field. /// The type of the field.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub type_: IdType, pub type_: IdType,
/// The class that own the field. /// The class that own the field.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub class_: IdType, pub class_: IdType,
} }
@ -669,20 +674,24 @@ impl<V: VisitorMut> VisitableMut<V> for IdField {
} }
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl IdField { impl IdField {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new( pub fn new(
#[pyo3(from_py_with = "crate::dex_string::as_dex_string")] name: DexString, #[cfg_attr(
feature = "python",
pyo3(from_py_with = "crate::dex_string::as_dex_string")
)]
name: DexString,
type_: IdType, type_: IdType,
class_: IdType, class_: IdType,
) -> Self { ) -> Self {
@ -709,7 +718,7 @@ impl IdField {
/// ) /// )
/// ); /// );
/// ``` /// ```
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_smali(smali_repr: &str) -> Result<Self> { pub fn from_smali(smali_repr: &str) -> Result<Self> {
let arrow_i = smali_repr.find("->"); let arrow_i = smali_repr.find("->");
if arrow_i.is_none() { if arrow_i.is_none() {
@ -803,17 +812,17 @@ impl SmaliName for IdField {
} }
/// The Id of a method. /// The Id of a method.
#[pyclass(eq, ord, hash, frozen)] #[cfg_attr(feature = "python", pyclass(eq, ord, hash, frozen))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct IdMethod { pub struct IdMethod {
/// The class containing the method. /// The class containing the method.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub class_: IdType, pub class_: IdType,
/// The prototype (aka type or signature) of the method. /// The prototype (aka type or signature) of the method.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub proto: IdMethodType, pub proto: IdMethodType,
/// The name of the method. /// The name of the method.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub name: DexString, pub name: DexString,
} }
@ -835,20 +844,24 @@ impl<V: VisitorMut> VisitableMut<V> for IdMethod {
} }
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl IdMethod { impl IdMethod {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new( pub fn new(
#[pyo3(from_py_with = "crate::dex_string::as_dex_string")] name: DexString, #[cfg_attr(
feature = "python",
pyo3(from_py_with = "crate::dex_string::as_dex_string")
)]
name: DexString,
proto: IdMethodType, proto: IdMethodType,
class_: IdType, class_: IdType,
) -> Self { ) -> Self {
@ -884,7 +897,7 @@ impl IdMethod {
/// ) /// )
/// ); /// );
/// ``` /// ```
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_smali(smali_repr: &str) -> Result<Self> { pub fn from_smali(smali_repr: &str) -> Result<Self> {
let arrow_i = smali_repr.find("->"); let arrow_i = smali_repr.find("->");
if arrow_i.is_none() { if arrow_i.is_none() {
@ -998,7 +1011,7 @@ impl SmaliName for IdMethod {
} }
} }
#[pyclass(eq, ord, hash, frozen)] #[cfg_attr(feature = "python", pyclass(eq, ord, hash, frozen))]
#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub struct IdEnum(pub IdField); pub struct IdEnum(pub IdField);
@ -1014,18 +1027,18 @@ impl<V: VisitorMut> VisitableMut<V> for IdEnum {
} }
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl IdEnum { impl IdEnum {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(val: IdField) -> Self { pub fn new(val: IdField) -> Self {
Self(val) Self(val)
} }

View file

@ -1,13 +1,13 @@
use crate::{Result, Visitable, VisitableMut, Visitor, VisitorMut}; use crate::{Result, Visitable, VisitableMut, Visitor, VisitorMut};
use pyo3::exceptions::PyTypeError;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp::{Ord, PartialOrd}; use std::cmp::{Ord, PartialOrd};
use std::collections::HashSet; use std::collections::HashSet;
use std::hash::Hash; use std::hash::Hash;
use pyo3::prelude::*; #[cfg(feature = "python")]
use pyo3::{exceptions::PyTypeError, prelude::*};
#[pyclass(eq, ord, frozen, hash)] #[cfg_attr(feature = "python", pyclass(eq, ord, frozen, hash))]
#[derive(Clone, PartialEq, Eq, Ord, PartialOrd)] #[derive(Clone, PartialEq, Eq, Ord, PartialOrd)]
pub struct DexString(pub androscalpel_serializer::StringDataItem); pub struct DexString(pub androscalpel_serializer::StringDataItem);
@ -149,6 +149,7 @@ impl Hash for DexString {
} }
} }
#[cfg(feature = "python")]
pub fn as_dex_string(obj: &Bound<'_, PyAny>) -> PyResult<DexString> { pub fn as_dex_string(obj: &Bound<'_, PyAny>) -> PyResult<DexString> {
if let Ok(string) = DexString::extract_bound(obj) { if let Ok(string) = DexString::extract_bound(obj) {
Ok(string) Ok(string)
@ -162,18 +163,18 @@ pub fn as_dex_string(obj: &Bound<'_, PyAny>) -> PyResult<DexString> {
} }
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl DexString { impl DexString {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(s: &str) -> Self { pub fn new(s: &str) -> Self {
s.into() s.into()
} }

View file

@ -3,6 +3,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashSet; use std::collections::HashSet;
#[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{ use crate::{
@ -12,45 +13,45 @@ use crate::{
use androscalpel_serializer::consts::*; use androscalpel_serializer::consts::*;
/// Represent a field. /// Represent a field.
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Field { pub struct Field {
/// The structure used to reference this field. /// The structure used to reference this field.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub descriptor: IdField, pub descriptor: IdField,
/// The field visibility /// The field visibility
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub visibility: FieldVisibility, pub visibility: FieldVisibility,
/// If the field is defined for the class globally /// If the field is defined for the class globally
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_static: bool, pub is_static: bool,
/// If the field is immutable after construction /// If the field is immutable after construction
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_final: bool, pub is_final: bool,
/// For thread safety /// For thread safety
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_volatile: bool, pub is_volatile: bool,
/// If the field should **not** be saved by default serialization /// If the field should **not** be saved by default serialization
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_transient: bool, pub is_transient: bool,
/// If the field is not defined in the source code /// If the field is not defined in the source code
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_synthetic: bool, pub is_synthetic: bool,
/// If the field is an enumerated value /// If the field is an enumerated value
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_enum: bool, pub is_enum: bool,
/// The default value of this field /// The default value of this field
pub value: Option<DexValue>, pub value: Option<DexValue>,
/// The annotations for this field /// The annotations for this field
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub annotations: Vec<DexAnnotationItem>, pub annotations: Vec<DexAnnotationItem>,
/// Hidden Api data. /// Hidden Api data.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub hiddenapi: Option<HiddenApiData>, pub hiddenapi: Option<HiddenApiData>,
} }
/// Represent the visibility of a field /// Represent the visibility of a field
#[pyclass(eq, eq_int)] #[cfg_attr(feature = "python", pyclass(eq, eq_int))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub enum FieldVisibility { pub enum FieldVisibility {
Public, Public,
@ -59,18 +60,18 @@ pub enum FieldVisibility {
None_, // Actually quite common None_, // Actually quite common
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl Field { impl Field {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(descriptor: IdField) -> Self { pub fn new(descriptor: IdField) -> Self {
Self { Self {
descriptor, descriptor,
@ -124,12 +125,14 @@ impl Field {
} }
/// Return the value as a python object /// Return the value as a python object
#[cfg(feature = "python")]
#[getter] #[getter]
pub fn get_value(&self) -> Option<DexValue> { pub fn get_value(&self) -> Option<DexValue> {
self.value.clone() self.value.clone()
} }
/// Set the value from a python object /// Set the value from a python object
#[cfg(feature = "python")]
#[setter] #[setter]
pub fn set_value(&mut self, ob: &Bound<'_, PyAny>) -> PyResult<()> { pub fn set_value(&mut self, ob: &Bound<'_, PyAny>) -> PyResult<()> {
self.value = Some(ob.extract()?); self.value = Some(ob.extract()?);

View file

@ -2,10 +2,11 @@
use crate::{Result, Visitable, VisitableMut, Visitor, VisitorMut}; use crate::{Result, Visitable, VisitableMut, Visitor, VisitorMut};
use log::warn; use log::warn;
#[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[pyclass] #[cfg_attr(feature = "python", pyclass)]
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
pub struct HiddenApiData { pub struct HiddenApiData {
pub permission: HiddenApiPermission, pub permission: HiddenApiPermission,
@ -56,7 +57,7 @@ impl<V: VisitorMut> VisitableMut<V> for HiddenApiData {
} }
} }
#[pyclass] #[cfg_attr(feature = "python", pyclass)]
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
pub enum HiddenApiPermission { pub enum HiddenApiPermission {
/// Interfaces that can be freely used and are supported as /// Interfaces that can be freely used and are supported as
@ -147,7 +148,7 @@ impl From<HiddenApiPermission> for androscalpel_serializer::HiddenApiValue {
} }
} }
#[pyclass] #[cfg_attr(feature = "python", pyclass)]
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)]
pub struct HiddenApiDomain { pub struct HiddenApiDomain {
pub is_core_platform_api: bool, pub is_core_platform_api: bool,

View file

@ -15,6 +15,7 @@ use androscalpel_serializer::Instruction as InsFormat;
use androscalpel_serializer::Serializable; use androscalpel_serializer::Serializable;
use anyhow::{anyhow, bail}; use anyhow::{anyhow, bail};
#[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
@ -31,7 +32,7 @@ const I32_MIN_AS_I64: i64 = i32::MIN as i64;
const I32_MAX_AS_I64: i64 = i32::MAX as i64; const I32_MAX_AS_I64: i64 = i32::MAX as i64;
const U16_MAX_AS_USIZE: usize = u16::MAX as usize; const U16_MAX_AS_USIZE: usize = u16::MAX as usize;
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub enum Instruction { pub enum Instruction {
/// Waste a cycle. /// Waste a cycle.
@ -2094,13 +2095,13 @@ macro_rules! raw_ins_invoke {
}}; }};
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl Instruction { impl Instruction {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
@ -6596,31 +6597,31 @@ impl Instruction {
} }
} }
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct CallSite { pub struct CallSite {
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub method_handle: MethodHandle, pub method_handle: MethodHandle,
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub name: DexString, pub name: DexString,
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub type_: IdMethodType, pub type_: IdMethodType,
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub args: Vec<DexValue>, pub args: Vec<DexValue>,
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl CallSite { impl CallSite {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new( pub fn new(
method_handle: MethodHandle, method_handle: MethodHandle,
name: DexString, name: DexString,

View file

@ -3,6 +3,7 @@
// python, TryInto should be prefered // python, TryInto should be prefered
use anyhow::Result; use anyhow::Result;
#[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
pub mod annotation; pub mod annotation;
@ -18,6 +19,7 @@ pub mod hiddenapi;
pub mod instructions; pub mod instructions;
pub mod method; pub mod method;
pub mod method_handle; pub mod method_handle;
#[cfg(feature = "python")]
pub mod py_utils; pub mod py_utils;
pub mod scalar; pub mod scalar;
pub mod value; pub mod value;
@ -44,6 +46,7 @@ pub use visitor::*;
mod tests; mod tests;
/// Androscalpel. /// Androscalpel.
#[cfg(feature = "python")]
#[pymodule] #[pymodule]
fn androscalpel(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { fn androscalpel(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
pyo3_log::init(); pyo3_log::init();
@ -90,6 +93,7 @@ fn androscalpel(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
} }
/// Dalvik opcode for Androscalpel. /// Dalvik opcode for Androscalpel.
#[cfg(feature = "python")]
fn androscalpel_ins(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { fn androscalpel_ins(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<ins::CallSite>()?; m.add_class::<ins::CallSite>()?;
m.add_class::<ins::Instruction>()?; m.add_class::<ins::Instruction>()?;

View file

@ -3,6 +3,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashSet; use std::collections::HashSet;
#[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::{ use crate::{
@ -12,67 +13,67 @@ use crate::{
use androscalpel_serializer::consts::*; use androscalpel_serializer::consts::*;
/// Represent a method. /// Represent a method.
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Method { pub struct Method {
/// The structure used to reference this method. /// The structure used to reference this method.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub descriptor: IdMethod, pub descriptor: IdMethod,
/// The field visibility. /// The field visibility.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub visibility: MethodVisibility, pub visibility: MethodVisibility,
/// Static methods do not take this in argument. /// Static methods do not take this in argument.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_static: bool, pub is_static: bool,
/// Final methods are not averridable. /// Final methods are not averridable.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_final: bool, pub is_final: bool,
/// Synchronized method automatically acquire their associated lock around call. /// Synchronized method automatically acquire their associated lock around call.
/// Can only be set in native method, (`[Self::is_native] = true`). /// Can only be set in native method, (`[Self::is_native] = true`).
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_synchronized: bool, pub is_synchronized: bool,
/// Bridge are automatically added by the compiler as a type-safe bridge. /// Bridge are automatically added by the compiler as a type-safe bridge.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_bridge: bool, pub is_bridge: bool,
/// If the last argument should be treated as a "rest" argument by compiler /// If the last argument should be treated as a "rest" argument by compiler
/// (for method of variable number of argument). /// (for method of variable number of argument).
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_varargs: bool, pub is_varargs: bool,
/// If the method is a native method. /// If the method is a native method.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_native: bool, pub is_native: bool,
/// Abstract methods are not implemented by the class. /// Abstract methods are not implemented by the class.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_abstract: bool, pub is_abstract: bool,
/// If the method must use strict rules for floating point arithmetic. /// If the method must use strict rules for floating point arithmetic.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_strictfp: bool, pub is_strictfp: bool,
/// Synthetic method are not directly defined in the source code. /// Synthetic method are not directly defined in the source code.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_synthetic: bool, pub is_synthetic: bool,
/// If the method is a constructor. /// If the method is a constructor.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_constructor: bool, pub is_constructor: bool,
/// If the method is declared as synchronize (just indicatif) /// If the method is declared as synchronize (just indicatif)
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub is_declared_syncrhonized: bool, pub is_declared_syncrhonized: bool,
/// The annotations for this method /// The annotations for this method
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub annotations: Vec<DexAnnotationItem>, pub annotations: Vec<DexAnnotationItem>,
/// The annotations for the parameters of this method method /// The annotations for the parameters of this method method
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub parameters_annotations: Vec<Vec<DexAnnotationItem>>, pub parameters_annotations: Vec<Vec<DexAnnotationItem>>,
/// Hidden Api data. /// Hidden Api data.
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub hiddenapi: Option<HiddenApiData>, pub hiddenapi: Option<HiddenApiData>,
/// The code of the method /// The code of the method
#[pyo3(get)] #[cfg_attr(feature = "python", pyo3(get))]
pub code: Option<Code>, pub code: Option<Code>,
} }
/// Represent the visibility of a field /// Represent the visibility of a field
#[pyclass(eq, eq_int)] #[cfg_attr(feature = "python", pyclass(eq, eq_int))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub enum MethodVisibility { pub enum MethodVisibility {
Public, Public,
@ -81,18 +82,18 @@ pub enum MethodVisibility {
None_, // Actually quite common None_, // Actually quite common
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl Method { impl Method {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(descriptor: IdMethod) -> Self { pub fn new(descriptor: IdMethod) -> Self {
// TODO: take code option as arg and set the default flags accordingly // TODO: take code option as arg and set the default flags accordingly
Self { Self {

View file

@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
use std::collections::HashSet; use std::collections::HashSet;
use std::hash::Hash; use std::hash::Hash;
#[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
use crate::dex_id::*; use crate::dex_id::*;
@ -13,7 +14,7 @@ use crate::{
}; };
/// The structure use to reference a method invocation. /// The structure use to reference a method invocation.
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub enum MethodHandle { pub enum MethodHandle {
StaticPut { field: IdField }, StaticPut { field: IdField },
@ -78,13 +79,13 @@ impl<V: VisitorMut> VisitableMut<V> for MethodHandle {
} }
} }
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl MethodHandle { impl MethodHandle {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }

View file

@ -8,23 +8,25 @@ use crate::{
DexString, DexValue, IdField, IdMethod, IdMethodType, IdType, MethodHandle, Visitable, DexString, DexValue, IdField, IdMethod, IdMethodType, IdType, MethodHandle, Visitable,
VisitableMut, Visitor, VisitorMut, VisitableMut, Visitor, VisitorMut,
}; };
#[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::prelude::*;
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub struct DexByte(pub i8); pub struct DexByte(pub i8);
#[pymethods]
#[cfg_attr(feature = "python", pymethods)]
impl DexByte { impl DexByte {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(val: i8) -> Self { pub fn new(val: i8) -> Self {
Self(val) Self(val)
} }
@ -42,21 +44,21 @@ impl DexByte {
} }
} }
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub struct DexShort(pub i16); pub struct DexShort(pub i16);
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl DexShort { impl DexShort {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(val: i16) -> Self { pub fn new(val: i16) -> Self {
Self(val) Self(val)
} }
@ -74,21 +76,21 @@ impl DexShort {
} }
} }
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub struct DexChar(pub u16); pub struct DexChar(pub u16);
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl DexChar { impl DexChar {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(val: u16) -> Self { pub fn new(val: u16) -> Self {
Self(val) Self(val)
} }
@ -106,21 +108,21 @@ impl DexChar {
} }
} }
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub struct DexInt(pub i32); pub struct DexInt(pub i32);
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl DexInt { impl DexInt {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(val: i32) -> Self { pub fn new(val: i32) -> Self {
Self(val) Self(val)
} }
@ -138,21 +140,21 @@ impl DexInt {
} }
} }
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub struct DexLong(pub i64); pub struct DexLong(pub i64);
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl DexLong { impl DexLong {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(val: i64) -> Self { pub fn new(val: i64) -> Self {
Self(val) Self(val)
} }
@ -170,21 +172,21 @@ impl DexLong {
} }
} }
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)]
pub struct DexFloat(pub f32); pub struct DexFloat(pub f32);
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl DexFloat { impl DexFloat {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(val: f32) -> Self { pub fn new(val: f32) -> Self {
Self(val) Self(val)
} }
@ -202,21 +204,21 @@ impl DexFloat {
} }
} }
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)]
pub struct DexDouble(pub f64); pub struct DexDouble(pub f64);
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl DexDouble { impl DexDouble {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(val: f64) -> Self { pub fn new(val: f64) -> Self {
Self(val) Self(val)
} }
@ -235,21 +237,21 @@ impl DexDouble {
} }
/* DexString is already define in lib.rs, TODO: move the version in lib.rs here /* DexString is already define in lib.rs, TODO: move the version in lib.rs here
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DexString(pub u32); pub struct DexString(pub u32);
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl DexString { impl DexString {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(val: u32) -> Self { pub fn new(val: u32) -> Self {
Self(val) Self(val)
} }
@ -268,21 +270,21 @@ impl DexString {
} }
*/ */
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub struct DexNull; pub struct DexNull;
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl DexNull { impl DexNull {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn _new() -> Self { pub fn _new() -> Self {
Self Self
} }
@ -296,21 +298,21 @@ impl DexNull {
} }
} }
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub struct DexBoolean(pub bool); pub struct DexBoolean(pub bool);
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl DexBoolean { impl DexBoolean {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn new(val: bool) -> Self { pub fn new(val: bool) -> Self {
Self(val) Self(val)
} }
@ -328,21 +330,21 @@ impl DexBoolean {
} }
} }
#[pyclass(eq)] #[cfg_attr(feature = "python", pyclass(eq))]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct DexArray(pub Vec<DexValue>); pub struct DexArray(pub Vec<DexValue>);
#[pymethods] #[cfg_attr(feature = "python", pymethods)]
impl DexArray { impl DexArray {
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?) Ok(serde_json::to_string(self)?)
} }
#[staticmethod] #[cfg_attr(feature = "python", staticmethod)]
pub fn from_json(json: &str) -> Result<Self> { pub fn from_json(json: &str) -> Result<Self> {
Ok(serde_json::from_str(json)?) Ok(serde_json::from_str(json)?)
} }
#[new] #[cfg_attr(feature = "python", new)]
pub fn _new(arr: Vec<DexValue>) -> Self { pub fn _new(arr: Vec<DexValue>) -> Self {
Self(arr) Self(arr)
} }

View file

@ -3,8 +3,8 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashSet; use std::collections::HashSet;
use pyo3::exceptions::PyTypeError; #[cfg(feature = "python")]
use pyo3::prelude::*; use pyo3::{exceptions::PyTypeError, prelude::*};
use crate::{ use crate::{
dex_id::*, scalar::*, DexAnnotation, DexString, MethodHandle, Result, Visitable, VisitableMut, dex_id::*, scalar::*, DexAnnotation, DexString, MethodHandle, Result, Visitable, VisitableMut,
@ -83,6 +83,7 @@ impl<V: VisitorMut> VisitableMut<V> for DexValue {
} }
} }
#[cfg(feature = "python")]
impl<'source> FromPyObject<'source> for DexValue { impl<'source> FromPyObject<'source> for DexValue {
fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult<Self> { fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult<Self> {
if let Ok(val) = DexByte::extract_bound(ob) { if let Ok(val) = DexByte::extract_bound(ob) {
@ -305,7 +306,7 @@ impl DexValue {
} }
} }
} }
#[cfg(feature = "python")]
impl<'py> IntoPyObject<'py> for DexValue { impl<'py> IntoPyObject<'py> for DexValue {
type Target = PyAny; type Target = PyAny;
type Output = Bound<'py, Self::Target>; type Output = Bound<'py, Self::Target>;