add platform list of platform api

This commit is contained in:
Jean-Marie 'Histausse' Mineau 2025-04-22 10:40:24 +02:00
parent 3cc02a3292
commit 1f2de8b60d
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
15 changed files with 654199 additions and 11 deletions

5
Cargo.lock generated
View file

@ -39,6 +39,7 @@ name = "androscalpel"
version = "0.1.0"
dependencies = [
"adler",
"androscalpel_platform_api_list",
"androscalpel_serializer",
"anyhow",
"apk_frauder",
@ -53,6 +54,10 @@ dependencies = [
"zip",
]
[[package]]
name = "androscalpel_platform_api_list"
version = "0.1.0"
[[package]]
name = "androscalpel_serializer"
version = "0.1.0"

View file

@ -4,6 +4,6 @@ members = [
"apk_frauder",
"androscalpel_serializer",
"androscalpel_serializer_derive",
"androscalpel",
"androscalpel", "androscalpel_platform_api_list",
]
resolver = "2"

View file

@ -11,6 +11,7 @@ crate-type = ["cdylib", "lib"]
[dependencies]
adler = "1.0.2"
androscalpel_serializer = { version = "0.1.0", path = "../androscalpel_serializer" }
androscalpel_platform_api_list = { version = "0.1.0", path = "../androscalpel_platform_api_list", optional = true }
anyhow = { version = "1.0.75", features = ["backtrace"] }
apk_frauder = { version = "0.1.0", path = "../apk_frauder" }
log = "0.4.20"
@ -26,8 +27,9 @@ zip = {version = "2.2.2", optional = true}
pretty_assertions = "1.4.1"
[features]
default = ["code-analysis"]
default = ["code-analysis", "platform-list"]
# 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"] # Currently not supported
external-zip-reader = ["zip"]
platform-list = ["androscalpel_platform_api_list"]
code-analysis = []

View file

@ -383,6 +383,12 @@ impl Class {
}
flags
}
/// Check if the class is a platform class (ie in the android SDK or a hidden API).
#[cfg(feature = "platform-list")]
pub fn is_platform_class(&self) -> bool {
self.descriptor.is_platform_class()
}
}
impl<V: Visitor> Visitable<V> for Class {

View file

@ -5,11 +5,11 @@ use std::cmp::{Ord, Ordering, PartialOrd};
use std::collections::HashSet;
use std::hash::Hash;
use anyhow::{Context, anyhow, bail};
use anyhow::{anyhow, bail, Context};
#[cfg(feature = "python")]
use pyo3::prelude::*;
use crate::{DexString, DexValue, Result, Visitable, VisitableMut, Visitor, VisitorMut, scalar::*};
use crate::{scalar::*, DexString, DexValue, Result, Visitable, VisitableMut, Visitor, VisitorMut};
use androscalpel_serializer::{StringDataItem, Uleb128};
/// The type of a method. The shorty is formated as described in
@ -353,13 +353,13 @@ impl IdType {
};
if let Some(mut new_type) = new_type {
if array_dimmention != 0 {
let mut data = vec![0u8; array_dimmention + new_type.0.0.data.len()];
let mut data = vec![0u8; array_dimmention + new_type.0 .0.data.len()];
for c in &mut data[..array_dimmention] {
*c = 0x5b;
}
data[array_dimmention..].copy_from_slice(&new_type.0.0.data);
new_type.0.0.data = data;
new_type.0.0.utf16_size.0 += array_dimmention as u32;
data[array_dimmention..].copy_from_slice(&new_type.0 .0.data);
new_type.0 .0.data = data;
new_type.0 .0.utf16_size.0 += array_dimmention as u32;
}
lst.push(new_type);
@ -446,8 +446,8 @@ impl IdType {
#[cfg_attr(feature = "python", staticmethod)]
pub fn array(type_: &IdType) -> Self {
let mut ty = type_.clone();
ty.0.0.utf16_size.0 += 1;
ty.0.0.data.insert(0, 0x5b);
ty.0 .0.utf16_size.0 += 1;
ty.0 .0.data.insert(0, 0x5b);
ty
}
@ -641,13 +641,23 @@ impl IdType {
types.insert(self.clone());
types
}
/// Check if the class is a platform class (ie in the android SDK or a hidden API).
#[cfg(feature = "platform-list")]
pub fn is_platform_class(&self) -> bool {
match self.try_to_smali() {
Ok(smali) => androscalpel_platform_api_list::is_platform_class(&smali),
Err(_) => false,
}
}
// TODO: TESTS
}
impl SmaliName for IdType {
/// Convert a descriptor to its smali representation.
fn try_to_smali(&self) -> Result<String> {
let r = (&self.0.0).try_into()?; // Anyhow conversion stuff
let r = (&self.0 .0).try_into()?; // Anyhow conversion stuff
Ok(r)
}
/// Convert a smali representation to its descriptor.
@ -795,6 +805,15 @@ impl IdField {
fields.insert(self.clone());
fields
}
/// Check if the field is a platform field (ie in the android SDK or a hidden API).
#[cfg(feature = "platform-list")]
pub fn is_platform_field(&self) -> bool {
match self.try_to_smali() {
Ok(smali) => androscalpel_platform_api_list::is_platform_field(&smali),
Err(_) => false,
}
}
}
impl Ord for IdField {
@ -992,6 +1011,15 @@ impl IdMethod {
method_ids.insert(self.clone());
method_ids
}
/// Check if the method is a platform method (ie in the android SDK or a hidden API).
#[cfg(feature = "platform-list")]
pub fn is_platform_method(&self) -> bool {
match self.try_to_smali() {
Ok(smali) => androscalpel_platform_api_list::is_platform_method(&smali),
Err(_) => false,
}
}
}
impl Ord for IdMethod {

View file

@ -255,6 +255,12 @@ impl Field {
pub fn has_annotations(&self) -> bool {
!self.annotations.is_empty()
}
/// Check if the field is a platform field (ie in the android SDK or a hidden API).
#[cfg(feature = "platform-list")]
pub fn is_platform_field(&self) -> bool {
self.descriptor.is_platform_field()
}
}
impl<V: Visitor> Visitable<V> for Field {

View file

@ -313,6 +313,12 @@ impl Method {
}
ins
}
/// Check if the method is a platform method (ie in the android SDK or a hidden API).
#[cfg(feature = "platform-list")]
pub fn is_platform_method(&self) -> bool {
self.descriptor.is_platform_method()
}
}
impl<V: Visitor> Visitable<V> for Method {

View file

@ -716,3 +716,11 @@ fn test_hidden_api() {
}
}
}
#[test]
fn test_is_platform_class() {
let activity = Class::new("Landroid/app/Activity;".into()).unwrap();
assert!(activity.is_platform_class());
let not_platform = Class::new("Landroid/app/NotAPlatformClass;".into()).unwrap();
assert!(!not_platform.is_platform_class());
}

View file

@ -0,0 +1,9 @@
[package]
name = "androscalpel_platform_api_list"
version = "0.1.0"
edition = "2024"
[dependencies]
[features]
sdk34 = []

View file

@ -0,0 +1,5 @@
# Android Platform API
List of android platform API (API that are either in the android SDK or hidden API).
The list is extracted from the default android emulator the respective SDKs.

View file

@ -0,0 +1,20 @@
pub mod sdk34;
pub use sdk34::*;
// TODO: automate addign a new SDK
// TODO: different version with different features
/// Test if the class is part of the platform classes.
pub fn is_platform_class(smali: &str) -> bool {
is_sdk34_platform_class(smali)
}
/// Test if the field is part of the platform classes.
pub fn is_platform_field(smali: &str) -> bool {
is_sdk34_platform_field(smali)
}
/// Test if the method is part of the platform classes.
pub fn is_platform_method(smali: &str) -> bool {
is_sdk34_platform_method(smali)
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,60 @@
use std::collections::HashSet;
use std::sync::LazyLock;
pub static PLATFORM_CLASSES_SDK34: LazyLock<HashSet<&'static str>> =
LazyLock::new(|| include_str!("classes.txt").lines().collect());
pub static PLATFORM_FIELDS_SDK34: LazyLock<HashSet<&'static str>> =
LazyLock::new(|| include_str!("fields.txt").lines().collect());
pub static PLATFORM_METHODS_SDK34: LazyLock<HashSet<&'static str>> =
LazyLock::new(|| include_str!("methods.txt").lines().collect());
/// Test if the class is part of the platform classes of the SDK 34.
pub fn is_sdk34_platform_class(smali: &str) -> bool {
PLATFORM_CLASSES_SDK34.contains(smali)
}
/// Test if the field is part of the platform classes of the SDK 34.
pub fn is_sdk34_platform_field(smali: &str) -> bool {
PLATFORM_FIELDS_SDK34.contains(smali)
}
/// Test if the method is part of the platform classes of the SDK 34.
pub fn is_sdk34_platform_method(smali: &str) -> bool {
PLATFORM_METHODS_SDK34.contains(smali)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_classes_sdk34_set() {
assert!(PLATFORM_CLASSES_SDK34
.contains("Landroid/accessibilityservice/AccessibilityGestureEvent;"));
let s: String = "Landroid/accessibilityservice/AccessibilityInputMethodSession;".into();
assert!(PLATFORM_CLASSES_SDK34.contains(s.as_str()));
}
#[test]
fn test_fields_sdk34_set() {
assert!(PLATFORM_FIELDS_SDK34.contains(
"Landroid/accessibilityservice/AccessibilityButtonController$$\
ExternalSyntheticLambda1;->f$0:Landroid/accessibilityservice/\
AccessibilityButtonController;"
));
let s: String = "Landroid/accessibilityservice/AccessibilityButtonController;->mLock:Ljava/lang/Object;".into();
assert!(PLATFORM_FIELDS_SDK34.contains(s.as_str()));
}
#[test]
fn test_methods_sdk34_set() {
assert!(PLATFORM_METHODS_SDK34
.contains("Landroid/accessibilityservice/AccessibilityButtonController$$ExternalSyntheticLambda1;->run()V"));
let s: String = "Landroid/accessibilityservice/AccessibilityButtonController;->\
$r8$lambda$h5Na0_pkg6ffhlKQPqxrTXannSI(\
Landroid/accessibilityservice/AccessibilityButtonController;\
Landroid/accessibilityservice/AccessibilityButtonController$AccessibilityButtonCallback;\
)V".into();
assert!(PLATFORM_METHODS_SDK34.contains(s.as_str()));
}
}