Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
S
SandHook
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
SandHook
Commits
5c250a7a
Commit
5c250a7a
authored
Feb 16, 2019
by
swift_gan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add dexmaker cache
parent
0b884655
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
4095 additions
and
24 deletions
+4095
-24
SandHook.java
hooklib/src/main/java/com/swift/sandhook/SandHook.java
+1
-1
build.gradle
xposedcompat/build.gradle
+1
-1
AnnotationId.java
xposedcompat/src/main/java/com/android/dx/AnnotationId.java
+257
-0
AppDataDirGuesser.java
...ompat/src/main/java/com/android/dx/AppDataDirGuesser.java
+225
-0
BinaryOp.java
xposedcompat/src/main/java/com/android/dx/BinaryOp.java
+129
-0
Code.java
xposedcompat/src/main/java/com/android/dx/Code.java
+922
-0
Comparison.java
xposedcompat/src/main/java/com/android/dx/Comparison.java
+77
-0
Constants.java
xposedcompat/src/main/java/com/android/dx/Constants.java
+72
-0
DexMaker.java
xposedcompat/src/main/java/com/android/dx/DexMaker.java
+700
-0
FieldId.java
xposedcompat/src/main/java/com/android/dx/FieldId.java
+77
-0
Label.java
xposedcompat/src/main/java/com/android/dx/Label.java
+92
-0
Local.java
xposedcompat/src/main/java/com/android/dx/Local.java
+75
-0
MethodId.java
xposedcompat/src/main/java/com/android/dx/MethodId.java
+131
-0
TypeId.java
xposedcompat/src/main/java/com/android/dx/TypeId.java
+153
-0
TypeList.java
xposedcompat/src/main/java/com/android/dx/TypeList.java
+67
-0
UnaryOp.java
xposedcompat/src/main/java/com/android/dx/UnaryOp.java
+44
-0
ProxyBuilder.java
...mpat/src/main/java/com/android/dx/stock/ProxyBuilder.java
+994
-0
XposedCompat.java
...in/java/com/swift/sandhook/xposedcompat/XposedCompat.java
+15
-1
DynamicBridge.java
.../swift/sandhook/xposedcompat/methodgen/DynamicBridge.java
+17
-10
HookerDexMaker.java
...swift/sandhook/xposedcompat/methodgen/HookerDexMaker.java
+32
-11
DexMakerUtils.java
.../com/swift/sandhook/xposedcompat/utils/DexMakerUtils.java
+14
-0
No files found.
hooklib/src/main/java/com/swift/sandhook/SandHook.java
View file @
5c250a7a
...
@@ -74,7 +74,7 @@ public class SandHook {
...
@@ -74,7 +74,7 @@ public class SandHook {
public
static
synchronized
void
hook
(
HookWrapper
.
HookEntity
entity
)
throws
HookErrorException
{
public
static
synchronized
void
hook
(
HookWrapper
.
HookEntity
entity
)
throws
HookErrorException
{
if
(
entity
==
null
)
if
(
entity
==
null
)
throw
new
HookErrorException
(
"null entity"
);
throw
new
HookErrorException
(
"null
hook
entity"
);
Member
target
=
entity
.
target
;
Member
target
=
entity
.
target
;
Method
hook
=
entity
.
hook
;
Method
hook
=
entity
.
hook
;
...
...
xposedcompat/build.gradle
View file @
5c250a7a
...
@@ -26,7 +26,7 @@ android {
...
@@ -26,7 +26,7 @@ android {
dependencies
{
dependencies
{
implementation
fileTree
(
include:
[
'*.jar'
],
dir:
'libs'
)
implementation
fileTree
(
include:
[
'*.jar'
],
dir:
'libs'
)
implementation
'com.
linkedin.dexmaker:dexmaker:2.21.0
'
implementation
'com.
jakewharton.android.repackaged:dalvik-dx:9.0.0_r3
'
compileOnly
project
(
':hooklib'
)
compileOnly
project
(
':hooklib'
)
}
}
...
...
xposedcompat/src/main/java/com/android/dx/AnnotationId.java
0 → 100755
View file @
5c250a7a
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
android
.
dx
;
import
com.android.dx.dex.file.ClassDefItem
;
import
com.android.dx.rop.annotation.Annotation
;
import
com.android.dx.rop.annotation.AnnotationVisibility
;
import
com.android.dx.rop.annotation.Annotations
;
import
com.android.dx.rop.annotation.NameValuePair
;
import
com.android.dx.rop.cst.*
;
import
java.lang.annotation.ElementType
;
import
java.util.HashMap
;
/**
* Identifies an annotation on a program element, see {@link ElementType}.
*
* Currently it is only targeting Class, Method, Field and Parameter because those are supported by
* {@link com.android.dx.dex.file.AnnotationsDirectoryItem} so far.
*
* <p><strong>NOTE:</strong>
* So far it only supports adding method annotation. The annotation of class, field and parameter
* will be implemented later.
*
* <p><strong>WARNING:</strong>
* The declared element of an annotation type should either have a default value or be set a value via
* {@code AnnotationId.set(Element)}. Otherwise it will incur
* {@link java.lang.annotation.IncompleteAnnotationException} when accessing the annotation element
* through reflection. The example is as follows:
* <pre>
* {@code @Retention(RetentionPolicy.RUNTIME)}
* {@code @Target({ElementType.METHOD})}
* {@code @interface MethodAnnotation {
* boolean elementBoolean();
* // boolean elementBoolean() default false;
* }
*
* TypeId<?> GENERATED = TypeId.get("LGenerated;");
* MethodId<?, Void> methodId = GENERATED.getMethod(VOID, "call");
* Code code = dexMaker.declare(methodId, PUBLIC);
* code.returnVoid();
*
* TypeId<MethodAnnotation> annotationTypeId = TypeId.get(MethodAnnotation.class);
* AnnotationId<?, MethodAnnotation> annotationId = AnnotationId.get(GENERATED,
* annotationTypeId, ElementType.METHOD);
*
* AnnotationId.Element element = new AnnotationId.Element("elementBoolean", true);
* annotationId.set(element);
* annotationId.addToMethod(dexMaker, methodId);
* }
* </pre>
*
* @param <D> the type that declares the program element.
* @param <V> the annotation type. It should be a known type before compile.
*/
public
final
class
AnnotationId
<
D
,
V
>
{
private
final
TypeId
<
D
>
declaringType
;
private
final
TypeId
<
V
>
type
;
/** The type of program element to be annotated */
private
final
ElementType
annotatedElement
;
/** The elements this annotation holds */
private
final
HashMap
<
String
,
NameValuePair
>
elements
;
private
AnnotationId
(
TypeId
<
D
>
declaringType
,
TypeId
<
V
>
type
,
ElementType
annotatedElement
)
{
this
.
declaringType
=
declaringType
;
this
.
type
=
type
;
this
.
annotatedElement
=
annotatedElement
;
this
.
elements
=
new
HashMap
<>();
}
/**
* Construct an instance. It initially contains no elements.
*
* @param declaringType the type declaring the program element.
* @param type the annotation type.
* @param annotatedElement the program element type to be annotated.
* @return an annotation {@code AnnotationId<D,V>} instance.
*/
public
static
<
D
,
V
>
AnnotationId
<
D
,
V
>
get
(
TypeId
<
D
>
declaringType
,
TypeId
<
V
>
type
,
ElementType
annotatedElement
)
{
if
(
annotatedElement
!=
ElementType
.
TYPE
&&
annotatedElement
!=
ElementType
.
METHOD
&&
annotatedElement
!=
ElementType
.
FIELD
&&
annotatedElement
!=
ElementType
.
PARAMETER
)
{
throw
new
IllegalArgumentException
(
"element type is not supported to annotate yet."
);
}
return
new
AnnotationId
<>(
declaringType
,
type
,
annotatedElement
);
}
/**
* Set an annotation element of this instance.
* If there is a preexisting element with the same name, it will be
* replaced by this method.
*
* @param element {@code non-null;} the annotation element to be set.
*/
public
void
set
(
Element
element
)
{
if
(
element
==
null
)
{
throw
new
NullPointerException
(
"element == null"
);
}
CstString
pairName
=
new
CstString
(
element
.
getName
());
Constant
pairValue
=
Element
.
toConstant
(
element
.
getValue
());
NameValuePair
nameValuePair
=
new
NameValuePair
(
pairName
,
pairValue
);
elements
.
put
(
element
.
getName
(),
nameValuePair
);
}
/**
* Add this annotation to a method.
*
* @param dexMaker DexMaker instance.
* @param method Method to be added to.
*/
public
void
addToMethod
(
DexMaker
dexMaker
,
MethodId
<?,
?>
method
)
{
if
(
annotatedElement
!=
ElementType
.
METHOD
)
{
throw
new
IllegalStateException
(
"This annotation is not for method"
);
}
if
(!
method
.
declaringType
.
equals
(
declaringType
))
{
throw
new
IllegalArgumentException
(
"Method"
+
method
+
"'s declaring type is inconsistent with"
+
this
);
}
ClassDefItem
classDefItem
=
dexMaker
.
getTypeDeclaration
(
declaringType
).
toClassDefItem
();
if
(
classDefItem
==
null
)
{
throw
new
NullPointerException
(
"No class defined item is found"
);
}
else
{
CstMethodRef
cstMethodRef
=
method
.
constant
;
if
(
cstMethodRef
==
null
)
{
throw
new
NullPointerException
(
"Method reference is NULL"
);
}
else
{
// Generate CstType
CstType
cstType
=
CstType
.
intern
(
type
.
ropType
);
// Generate Annotation
Annotation
annotation
=
new
Annotation
(
cstType
,
AnnotationVisibility
.
RUNTIME
);
// Add generated annotation
Annotations
annotations
=
new
Annotations
();
for
(
NameValuePair
nvp
:
elements
.
values
())
{
annotation
.
add
(
nvp
);
}
annotations
.
add
(
annotation
);
classDefItem
.
addMethodAnnotations
(
cstMethodRef
,
annotations
,
dexMaker
.
getDexFile
());
}
}
}
/**
* A wrapper of <code>NameValuePair</code> represents a (name, value) pair used as the contents
* of an annotation.
*
* An {@code Element} instance is stored in {@code AnnotationId.elements} by calling {@code
* AnnotationId.set(Element)}.
*
* <p><strong>WARNING: </strong></p>
* the name should be exact same as the annotation element declared in the annotation type
* which is referred by field {@code AnnotationId.type},otherwise the annotation will fail
* to add and {@code java.lang.reflect.Method.getAnnotations()} will return nothing.
*
*/
public
static
final
class
Element
{
/** {@code non-null;} the name */
private
final
String
name
;
/** {@code non-null;} the value */
private
final
Object
value
;
/**
* Construct an instance.
*
* @param name {@code non-null;} the name
* @param value {@code non-null;} the value
*/
public
Element
(
String
name
,
Object
value
)
{
if
(
name
==
null
)
{
throw
new
NullPointerException
(
"name == null"
);
}
if
(
value
==
null
)
{
throw
new
NullPointerException
(
"value == null"
);
}
this
.
name
=
name
;
this
.
value
=
value
;
}
public
String
getName
()
{
return
name
;
}
public
Object
getValue
()
{
return
value
;
}
/** {@inheritDoc} */
@Override
public
String
toString
()
{
return
"["
+
name
+
", "
+
value
+
"]"
;
}
/** {@inheritDoc} */
@Override
public
int
hashCode
()
{
return
name
.
hashCode
()
*
31
+
value
.
hashCode
();
}
/** {@inheritDoc} */
@Override
public
boolean
equals
(
Object
other
)
{
if
(!
(
other
instanceof
Element
))
{
return
false
;
}
Element
otherElement
=
(
Element
)
other
;
return
name
.
equals
(
otherElement
.
name
)
&&
value
.
equals
(
otherElement
.
value
);
}
/**
* Convert a value of an element to a {@code Constant}.
* <p><strong>Warning:</strong> Array or TypeId value is not supported yet.
*
* @param value an annotation element value.
* @return a Constant
*/
static
Constant
toConstant
(
Object
value
)
{
Class
clazz
=
value
.
getClass
();
if
(
clazz
.
isEnum
())
{
CstString
descriptor
=
new
CstString
(
TypeId
.
get
(
clazz
).
getName
());
CstString
name
=
new
CstString
(((
Enum
)
value
).
name
());
CstNat
cstNat
=
new
CstNat
(
name
,
descriptor
);
return
new
CstEnumRef
(
cstNat
);
}
else
if
(
clazz
.
isArray
())
{
throw
new
UnsupportedOperationException
(
"Array is not supported yet"
);
}
else
if
(
value
instanceof
TypeId
)
{
throw
new
UnsupportedOperationException
(
"TypeId is not supported yet"
);
}
else
{
return
Constants
.
getConstant
(
value
);
}
}
}
}
xposedcompat/src/main/java/com/android/dx/AppDataDirGuesser.java
0 → 100755
View file @
5c250a7a
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
android
.
dx
;
import
java.io.File
;
import
java.lang.reflect.Field
;
import
java.lang.reflect.Method
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* Uses heuristics to guess the application's private data directory.
*/
class
AppDataDirGuesser
{
// Copied from UserHandle, indicates range of uids allocated for a user.
public
static
final
int
PER_USER_RANGE
=
100000
;
public
File
guess
()
{
try
{
ClassLoader
classLoader
=
guessSuitableClassLoader
();
// Check that we have an instance of the PathClassLoader.
Class
<?>
clazz
=
Class
.
forName
(
"dalvik.system.PathClassLoader"
);
clazz
.
cast
(
classLoader
);
// Use the toString() method to calculate the data directory.
String
pathFromThisClassLoader
=
getPathFromThisClassLoader
(
classLoader
,
clazz
);
File
[]
results
=
guessPath
(
pathFromThisClassLoader
);
if
(
results
.
length
>
0
)
{
return
results
[
0
];
}
}
catch
(
ClassCastException
ignored
)
{
}
catch
(
ClassNotFoundException
ignored
)
{
}
return
null
;
}
private
ClassLoader
guessSuitableClassLoader
()
{
return
AppDataDirGuesser
.
class
.
getClassLoader
();
}
private
String
getPathFromThisClassLoader
(
ClassLoader
classLoader
,
Class
<?>
pathClassLoaderClass
)
{
// Prior to ICS, we can simply read the "path" field of the
// PathClassLoader.
try
{
Field
pathField
=
pathClassLoaderClass
.
getDeclaredField
(
"path"
);
pathField
.
setAccessible
(
true
);
return
(
String
)
pathField
.
get
(
classLoader
);
}
catch
(
NoSuchFieldException
ignored
)
{
}
catch
(
IllegalAccessException
ignored
)
{
}
catch
(
ClassCastException
ignored
)
{
}
// Parsing toString() method: yuck. But no other way to get the path.
String
result
=
classLoader
.
toString
();
return
processClassLoaderString
(
result
);
}
/**
* Given the result of a ClassLoader.toString() call, process the result so that guessPath
* can use it. There are currently two variants. For Android 4.3 and later, the string
* "DexPathList" should be recognized and the array of dex path elements is parsed. for
* earlier versions, the last nested array ('[' ... ']') is enclosing the string we are
* interested in.
*/
static
String
processClassLoaderString
(
String
input
)
{
if
(
input
.
contains
(
"DexPathList"
))
{
return
processClassLoaderString43OrLater
(
input
);
}
else
{
return
processClassLoaderString42OrEarlier
(
input
);
}
}
private
static
String
processClassLoaderString42OrEarlier
(
String
input
)
{
/* The toString output looks like this:
* dalvik.system.PathClassLoader[dexPath=path/to/apk,libraryPath=path/to/libs]
*/
int
index
=
input
.
lastIndexOf
(
'['
);
input
=
(
index
==
-
1
)
?
input
:
input
.
substring
(
index
+
1
);
index
=
input
.
indexOf
(
']'
);
input
=
(
index
==
-
1
)
?
input
:
input
.
substring
(
0
,
index
);
return
input
;
}
private
static
String
processClassLoaderString43OrLater
(
String
input
)
{
/* The toString output looks like this:
* dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/{NAME}", ...], nativeLibraryDirectories=[...]]]
*/
int
start
=
input
.
indexOf
(
"DexPathList"
)
+
"DexPathList"
.
length
();
if
(
input
.
length
()
>
start
+
4
)
{
// [[ + ]]
String
trimmed
=
input
.
substring
(
start
);
int
end
=
trimmed
.
indexOf
(
']'
);
if
(
trimmed
.
charAt
(
0
)
==
'['
&&
trimmed
.
charAt
(
1
)
==
'['
&&
end
>=
0
)
{
trimmed
=
trimmed
.
substring
(
2
,
end
);
// Comma-separated list, Arrays.toString output.
String
split
[]
=
trimmed
.
split
(
","
);
// Clean up parts. Each path element is the type of the element plus the path in
// quotes.
for
(
int
i
=
0
;
i
<
split
.
length
;
i
++)
{
int
quoteStart
=
split
[
i
].
indexOf
(
'"'
);
int
quoteEnd
=
split
[
i
].
lastIndexOf
(
'"'
);
if
(
quoteStart
>
0
&&
quoteStart
<
quoteEnd
)
{
split
[
i
]
=
split
[
i
].
substring
(
quoteStart
+
1
,
quoteEnd
);
}
}
// Need to rejoin components.
StringBuilder
sb
=
new
StringBuilder
();
for
(
String
s
:
split
)
{
if
(
sb
.
length
()
>
0
)
{
sb
.
append
(
':'
);
}
sb
.
append
(
s
);
}
return
sb
.
toString
();
}
}
// This is technically a parsing failure. Return the original string, maybe a later
// stage can still salvage this.
return
input
;
}
File
[]
guessPath
(
String
input
)
{
List
<
File
>
results
=
new
ArrayList
<>();
for
(
String
potential
:
splitPathList
(
input
))
{
if
(!
potential
.
startsWith
(
"/data/app/"
))
{
continue
;
}
int
start
=
"/data/app/"
.
length
();
int
end
=
potential
.
lastIndexOf
(
".apk"
);
if
(
end
!=
potential
.
length
()
-
4
)
{
continue
;
}
int
dash
=
potential
.
indexOf
(
"-"
);
if
(
dash
!=
-
1
)
{
end
=
dash
;
}
String
packageName
=
potential
.
substring
(
start
,
end
);
File
dataDir
=
getWriteableDirectory
(
"/data/data/"
+
packageName
);
if
(
dataDir
==
null
)
{
// If we can't access "/data/data", try to guess user specific data directory.
dataDir
=
guessUserDataDirectory
(
packageName
);
}
if
(
dataDir
!=
null
)
{
File
cacheDir
=
new
File
(
dataDir
,
"cache"
);
// The cache directory might not exist -- create if necessary
if
(
fileOrDirExists
(
cacheDir
)
||
cacheDir
.
mkdir
())
{
if
(
isWriteableDirectory
(
cacheDir
))
{
results
.
add
(
cacheDir
);
}
}
}
}
return
results
.
toArray
(
new
File
[
results
.
size
()]);
}
static
String
[]
splitPathList
(
String
input
)
{
String
trimmed
=
input
;
if
(
input
.
startsWith
(
"dexPath="
))
{
int
start
=
"dexPath="
.
length
();
int
end
=
input
.
indexOf
(
','
);
trimmed
=
(
end
==
-
1
)
?
input
.
substring
(
start
)
:
input
.
substring
(
start
,
end
);
}
return
trimmed
.
split
(
":"
);
}
boolean
fileOrDirExists
(
File
file
)
{
return
file
.
exists
();
}
boolean
isWriteableDirectory
(
File
file
)
{
return
file
.
isDirectory
()
&&
file
.
canWrite
();
}
Integer
getProcessUid
()
{
/* Uses reflection to try to fetch process UID. It will only work when executing on
* Android device. Otherwise, returns null.
*/
try
{
Method
myUid
=
Class
.
forName
(
"android.os.Process"
).
getMethod
(
"myUid"
);
// Invoke the method on a null instance, since it's a static method.
return
(
Integer
)
myUid
.
invoke
(
/* instance= */
null
);
}
catch
(
Exception
e
)
{
// Catch any exceptions thrown and default to returning a null.
return
null
;
}
}
File
guessUserDataDirectory
(
String
packageName
)
{
Integer
uid
=
getProcessUid
();
if
(
uid
==
null
)
{
// If we couldn't retrieve process uid, return null.
return
null
;
}
// We're trying to get the ID of the Android user that's running the process. It can be
// inferred from the UID of the current process.
int
userId
=
uid
/
PER_USER_RANGE
;
return
getWriteableDirectory
(
String
.
format
(
"/data/user/%d/%s"
,
userId
,
packageName
));
}
private
File
getWriteableDirectory
(
String
pathName
)
{
File
dir
=
new
File
(
pathName
);
return
isWriteableDirectory
(
dir
)
?
dir
:
null
;
}
}
xposedcompat/src/main/java/com/android/dx/BinaryOp.java
0 → 100755
View file @
5c250a7a
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
android
.
dx
;
import
com.android.dx.rop.code.Rop
;
import
com.android.dx.rop.code.Rops
;
import
com.android.dx.rop.type.TypeList
;
/**
* An operation on two values of the same type.
*
* <p>Math operations ({@link #ADD}, {@link #SUBTRACT}, {@link #MULTIPLY},
* {@link #DIVIDE}, and {@link #REMAINDER}) support ints, longs, floats and
* doubles.
*
* <p>Bit operations ({@link #AND}, {@link #OR}, {@link #XOR}, {@link
* #SHIFT_LEFT}, {@link #SHIFT_RIGHT}, {@link #UNSIGNED_SHIFT_RIGHT}) support
* ints and longs.
*
* <p>Division by zero behaves differently depending on the operand type.
* For int and long operands, {@link #DIVIDE} and {@link #REMAINDER} throw
* {@link ArithmeticException} if {@code b == 0}. For float and double operands,
* the operations return {@code NaN}.
*/
public
enum
BinaryOp
{
/** {@code a + b} */
ADD
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opAdd
(
types
);
}
},
/** {@code a - b} */
SUBTRACT
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opSub
(
types
);
}
},
/** {@code a * b} */
MULTIPLY
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opMul
(
types
);
}
},
/** {@code a / b} */
DIVIDE
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opDiv
(
types
);
}
},
/** {@code a % b} */
REMAINDER
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opRem
(
types
);
}
},
/** {@code a & b} */
AND
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opAnd
(
types
);
}
},
/** {@code a | b} */
OR
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opOr
(
types
);
}
},
/** {@code a ^ b} */
XOR
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opXor
(
types
);
}
},
/** {@code a << b} */
SHIFT_LEFT
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opShl
(
types
);
}
},
/** {@code a >> b} */
SHIFT_RIGHT
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opShr
(
types
);
}
},
/** {@code a >>> b} */
UNSIGNED_SHIFT_RIGHT
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opUshr
(
types
);
}
};
abstract
Rop
rop
(
TypeList
types
);
}
xposedcompat/src/main/java/com/android/dx/Code.java
0 → 100755
View file @
5c250a7a
This diff is collapsed.
Click to expand it.
xposedcompat/src/main/java/com/android/dx/Comparison.java
0 → 100755
View file @
5c250a7a
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
android
.
dx
;
import
com.android.dx.rop.code.Rop
;
import
com.android.dx.rop.code.Rops
;
import
com.android.dx.rop.type.TypeList
;
/**
* A comparison between two values of the same type.
*/
public
enum
Comparison
{
/** {@code a < b}. Supports int only. */
LT
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opIfLt
(
types
);
}
},
/** {@code a <= b}. Supports int only. */
LE
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opIfLe
(
types
);
}
},
/** {@code a == b}. Supports int and reference types. */
EQ
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opIfEq
(
types
);
}
},
/** {@code a >= b}. Supports int only. */
GE
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opIfGe
(
types
);
}
},
/** {@code a > b}. Supports int only. */
GT
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opIfGt
(
types
);
}
},
/** {@code a != b}. Supports int and reference types. */
NE
()
{
@Override
Rop
rop
(
TypeList
types
)
{
return
Rops
.
opIfNe
(
types
);
}
};
abstract
Rop
rop
(
TypeList
types
);
}
xposedcompat/src/main/java/com/android/dx/Constants.java
0 → 100755
View file @
5c250a7a
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
android
.
dx
;
import
com.android.dx.rop.cst.CstBoolean
;
import
com.android.dx.rop.cst.CstByte
;
import
com.android.dx.rop.cst.CstChar
;
import
com.android.dx.rop.cst.CstDouble
;
import
com.android.dx.rop.cst.CstFloat
;
import
com.android.dx.rop.cst.CstInteger
;
import
com.android.dx.rop.cst.CstKnownNull
;
import
com.android.dx.rop.cst.CstLong
;
import
com.android.dx.rop.cst.CstShort
;
import
com.android.dx.rop.cst.CstString
;
import
com.android.dx.rop.cst.CstType
;
import
com.android.dx.rop.cst.TypedConstant
;
/**
* Factory for rop constants.
*/
final
class
Constants
{
private
Constants
()
{}
/**
* Returns a rop constant for the specified value.
*
* @param value null, a boxed primitive, String, Class, or TypeId.
*/
static
TypedConstant
getConstant
(
Object
value
)
{
if
(
value
==
null
)
{
return
CstKnownNull
.
THE_ONE
;
}
else
if
(
value
instanceof
Boolean
)
{
return
CstBoolean
.
make
((
Boolean
)
value
);
}
else
if
(
value
instanceof
Byte
)
{
return
CstByte
.
make
((
Byte
)
value
);
}
else
if
(
value
instanceof
Character
)
{
return
CstChar
.
make
((
Character
)
value
);
}
else
if
(
value
instanceof
Double
)
{
return
CstDouble
.
make
(
Double
.
doubleToLongBits
((
Double
)
value
));
}
else
if
(
value
instanceof
Float
)
{
return
CstFloat
.
make
(
Float
.
floatToIntBits
((
Float
)
value
));
}
else
if
(
value
instanceof
Integer
)
{
return
CstInteger
.
make
((
Integer
)
value
);
}
else
if
(
value
instanceof
Long
)
{
return
CstLong
.
make
((
Long
)
value
);
}
else
if
(
value
instanceof
Short
)
{
return
CstShort
.
make
((
Short
)
value
);
}
else
if
(
value
instanceof
String
)
{
return
new
CstString
((
String
)
value
);
}
else
if
(
value
instanceof
Class
)
{
return
new
CstType
(
TypeId
.
get
((
Class
<?>)
value
).
ropType
);
}
else
if
(
value
instanceof
TypeId
)
{
return
new
CstType
(((
TypeId
)
value
).
ropType
);
}
else
{
throw
new
UnsupportedOperationException
(
"Not a constant: "
+
value
);
}
}
}
xposedcompat/src/main/java/com/android/dx/DexMaker.java
0 → 100755
View file @
5c250a7a
This diff is collapsed.
Click to expand it.
xposedcompat/src/main/java/com/android/dx/FieldId.java
0 → 100755
View file @
5c250a7a
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
android
.
dx
;
import
com.android.dx.rop.cst.CstFieldRef
;
import
com.android.dx.rop.cst.CstNat
;
import
com.android.dx.rop.cst.CstString
;
/**
* Identifies a field.
*
* @param <D> the type declaring this field
* @param <V> the type of value this field holds
*/
public
final
class
FieldId
<
D
,
V
>
{
final
TypeId
<
D
>
declaringType
;
final
TypeId
<
V
>
type
;
final
String
name
;
/** cached converted state */
final
CstNat
nat
;
final
CstFieldRef
constant
;
FieldId
(
TypeId
<
D
>
declaringType
,
TypeId
<
V
>
type
,
String
name
)
{
if
(
declaringType
==
null
||
type
==
null
||
name
==
null
)
{
throw
new
NullPointerException
();
}
this
.
declaringType
=
declaringType
;
this
.
type
=
type
;
this
.
name
=
name
;
this
.
nat
=
new
CstNat
(
new
CstString
(
name
),
new
CstString
(
type
.
name
));
this
.
constant
=
new
CstFieldRef
(
declaringType
.
constant
,
nat
);
}
public
TypeId
<
D
>
getDeclaringType
()
{
return
declaringType
;
}
public
TypeId
<
V
>
getType
()
{
return
type
;
}
public
String
getName
()
{
return
name
;
}
@Override
public
boolean
equals
(
Object
o
)
{
return
o
instanceof
FieldId
&&
((
FieldId
<?,
?>)
o
).
declaringType
.
equals
(
declaringType
)
&&
((
FieldId
<?,
?>)
o
).
name
.
equals
(
name
);
}
@Override
public
int
hashCode
()
{
return
declaringType
.
hashCode
()
+
37
*
name
.
hashCode
();
}
@Override
public
String
toString
()
{
return
declaringType
+
"."
+
name
;
}
}
xposedcompat/src/main/java/com/android/dx/Label.java
0 → 100755
View file @
5c250a7a
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
android
.
dx
;
import
com.android.dx.rop.code.BasicBlock
;
import
com.android.dx.rop.code.Insn
;
import
com.android.dx.rop.code.InsnList
;
import
com.android.dx.util.IntList
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
/**
* A branch target in a list of instructions.
*/
public
final
class
Label
{
final
List
<
Insn
>
instructions
=
new
ArrayList
<>();
Code
code
;
boolean
marked
=
false
;
/** an immutable list of labels corresponding to the types in the catch list */
List
<
Label
>
catchLabels
=
Collections
.
emptyList
();
/** contains the next instruction if no branch occurs */
Label
primarySuccessor
;
/** contains the instruction to jump to if the if is true */
Label
alternateSuccessor
;
int
id
=
-
1
;
public
Label
()
{}
boolean
isEmpty
()
{
return
instructions
.
isEmpty
();
}
void
compact
()
{
for
(
int
i
=
0
;
i
<
catchLabels
.
size
();
i
++)
{
while
(
catchLabels
.
get
(
i
).
isEmpty
())
{
catchLabels
.
set
(
i
,
catchLabels
.
get
(
i
).
primarySuccessor
);
}
}
while
(
primarySuccessor
!=
null
&&
primarySuccessor
.
isEmpty
())
{
primarySuccessor
=
primarySuccessor
.
primarySuccessor
;
}
while
(
alternateSuccessor
!=
null
&&
alternateSuccessor
.
isEmpty
())
{
alternateSuccessor
=
alternateSuccessor
.
primarySuccessor
;
}
}
BasicBlock
toBasicBlock
()
{
InsnList
result
=
new
InsnList
(
instructions
.
size
());
for
(
int
i
=
0
;
i
<
instructions
.
size
();
i
++)
{
result
.
set
(
i
,
instructions
.
get
(
i
));
}
result
.
setImmutable
();
int
primarySuccessorIndex
=
-
1
;
IntList
successors
=
new
IntList
();
for
(
Label
catchLabel
:
catchLabels
)
{
successors
.
add
(
catchLabel
.
id
);
}
if
(
primarySuccessor
!=
null
)
{
primarySuccessorIndex
=
primarySuccessor
.
id
;
successors
.
add
(
primarySuccessorIndex
);
}
if
(
alternateSuccessor
!=
null
)
{
successors
.
add
(
alternateSuccessor
.
id
);
}
successors
.
setImmutable
();
return
new
BasicBlock
(
id
,
result
,
successors
,
primarySuccessorIndex
);
}
}
xposedcompat/src/main/java/com/android/dx/Local.java
0 → 100755
View file @
5c250a7a
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
android
.
dx
;
import
com.android.dx.rop.code.RegisterSpec
;
/**
* A temporary variable that holds a single value of a known type.
*/
public
final
class
Local
<
T
>
{
private
final
Code
code
;
final
TypeId
<
T
>
type
;
private
int
reg
=
-
1
;
private
RegisterSpec
spec
;
private
Local
(
Code
code
,
TypeId
<
T
>
type
)
{
this
.
code
=
code
;
this
.
type
=
type
;
}
static
<
T
>
Local
<
T
>
get
(
Code
code
,
TypeId
<
T
>
type
)
{
return
new
Local
<
T
>(
code
,
type
);
}
/**
* Assigns registers to this local.
*
* @return the number of registers required.
*/
int
initialize
(
int
nextAvailableRegister
)
{
this
.
reg
=
nextAvailableRegister
;
this
.
spec
=
RegisterSpec
.
make
(
nextAvailableRegister
,
type
.
ropType
);
return
size
();
}
/**
* Returns the number of registered required to hold this local.
*/
int
size
()
{
return
type
.
ropType
.
getCategory
();
}
RegisterSpec
spec
()
{
if
(
spec
==
null
)
{
code
.
initializeLocals
();
if
(
spec
==
null
)
{
throw
new
AssertionError
();
}
}
return
spec
;
}
public
TypeId
getType
()
{
return
type
;
}
@Override
public
String
toString
()
{
return
"v"
+
reg
+
"("
+
type
+
")"
;
}
}
xposedcompat/src/main/java/com/android/dx/MethodId.java
0 → 100755
View file @
5c250a7a
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
android
.
dx
;
import
com.android.dx.rop.cst.CstMethodRef
;
import
com.android.dx.rop.cst.CstNat
;
import
com.android.dx.rop.cst.CstString
;
import
com.android.dx.rop.type.Prototype
;
import
java.util.List
;
/**
* Identifies a method or constructor.
*
* @param <D> the type declaring this field
* @param <R> the return type of this method
*/
public
final
class
MethodId
<
D
,
R
>
{
final
TypeId
<
D
>
declaringType
;
final
TypeId
<
R
>
returnType
;
final
String
name
;
final
TypeList
parameters
;
/** cached converted state */
final
CstNat
nat
;
final
CstMethodRef
constant
;
MethodId
(
TypeId
<
D
>
declaringType
,
TypeId
<
R
>
returnType
,
String
name
,
TypeList
parameters
)
{
if
(
declaringType
==
null
||
returnType
==
null
||
name
==
null
||
parameters
==
null
)
{
throw
new
NullPointerException
();
}
this
.
declaringType
=
declaringType
;
this
.
returnType
=
returnType
;
this
.
name
=
name
;
this
.
parameters
=
parameters
;
this
.
nat
=
new
CstNat
(
new
CstString
(
name
),
new
CstString
(
descriptor
(
false
)));
this
.
constant
=
new
CstMethodRef
(
declaringType
.
constant
,
nat
);
}
public
TypeId
<
D
>
getDeclaringType
()
{
return
declaringType
;
}
public
TypeId
<
R
>
getReturnType
()
{
return
returnType
;
}
/**
* Returns true if this method is a constructor for its declaring class.
*/
public
boolean
isConstructor
()
{
return
name
.
equals
(
"<init>"
);
}
/**
* Returns true if this method is the static initializer for its declaring class.
*/
public
boolean
isStaticInitializer
()
{
return
name
.
equals
(
"<clinit>"
);
}
/**
* Returns the method's name. This is "<init>" if this is a constructor
* or "<clinit>" if a static initializer
*/
public
String
getName
()
{
return
name
;
}
public
List
<
TypeId
<?>>
getParameters
()
{
return
parameters
.
asList
();
}
/**
* Returns a descriptor like "(Ljava/lang/Class;[I)Ljava/lang/Object;".
*/
String
descriptor
(
boolean
includeThis
)
{
StringBuilder
result
=
new
StringBuilder
();
result
.
append
(
"("
);
if
(
includeThis
)
{
result
.
append
(
declaringType
.
name
);
}
for
(
TypeId
t
:
parameters
.
types
)
{
result
.
append
(
t
.
name
);
}
result
.
append
(
")"
);
result
.
append
(
returnType
.
name
);
return
result
.
toString
();
}
Prototype
prototype
(
boolean
includeThis
)
{
return
Prototype
.
intern
(
descriptor
(
includeThis
));
}
@Override
public
boolean
equals
(
Object
o
)
{
return
o
instanceof
MethodId
&&
((
MethodId
<?,
?>)
o
).
declaringType
.
equals
(
declaringType
)
&&
((
MethodId
<?,
?>)
o
).
name
.
equals
(
name
)
&&
((
MethodId
<?,
?>)
o
).
parameters
.
equals
(
parameters
)
&&
((
MethodId
<?,
?>)
o
).
returnType
.
equals
(
returnType
);
}
@Override
public
int
hashCode
()
{
int
result
=
17
;
result
=
31
*
result
+
declaringType
.
hashCode
();
result
=
31
*
result
+
name
.
hashCode
();
result
=
31
*
result
+
parameters
.
hashCode
();
result
=
31
*
result
+
returnType
.
hashCode
();
return
result
;
}
@Override
public
String
toString
()
{
return
declaringType
+
"."
+
name
+
"("
+
parameters
+
")"
;
}
}
xposedcompat/src/main/java/com/android/dx/TypeId.java
0 → 100755
View file @
5c250a7a
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
android
.
dx
;
import
com.android.dx.rop.cst.CstType
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* A primitive type, interface or class.
*
* <p><strong>Warning:</strong> Use care when dealing with boxed primitive
* types. Java's lack of support for parameterized primitive types means that
* a primitive type like {@code int} and its boxed type {@code
* java.lang.Integer} have the same type parameter: {@code TypeId<Integer>}.
* These types are different and it will be a runtime error if the boxed type
* {@code java.lang.Integer} is used where the primitive type {@code int} is
* expected.
*/
public
final
class
TypeId
<
T
>
{
/** The {@code boolean} primitive type. */
public
static
final
TypeId
<
Boolean
>
BOOLEAN
=
new
TypeId
<>(
com
.
android
.
dx
.
rop
.
type
.
Type
.
BOOLEAN
);
/** The {@code byte} primitive type. */
public
static
final
TypeId
<
Byte
>
BYTE
=
new
TypeId
<>(
com
.
android
.
dx
.
rop
.
type
.
Type
.
BYTE
);
/** The {@code char} primitive type. */
public
static
final
TypeId
<
Character
>
CHAR
=
new
TypeId
<>(
com
.
android
.
dx
.
rop
.
type
.
Type
.
CHAR
);
/** The {@code double} primitive type. */
public
static
final
TypeId
<
Double
>
DOUBLE
=
new
TypeId
<>(
com
.
android
.
dx
.
rop
.
type
.
Type
.
DOUBLE
);
/** The {@code float} primitive type. */
public
static
final
TypeId
<
Float
>
FLOAT
=
new
TypeId
<>(
com
.
android
.
dx
.
rop
.
type
.
Type
.
FLOAT
);
/** The {@code int} primitive type. */
public
static
final
TypeId
<
Integer
>
INT
=
new
TypeId
<>(
com
.
android
.
dx
.
rop
.
type
.
Type
.
INT
);
/** The {@code long} primitive type. */
public
static
final
TypeId
<
Long
>
LONG
=
new
TypeId
<>(
com
.
android
.
dx
.
rop
.
type
.
Type
.
LONG
);
/** The {@code short} primitive type. */
public
static
final
TypeId
<
Short
>
SHORT
=
new
TypeId
<>(
com
.
android
.
dx
.
rop
.
type
.
Type
.
SHORT
);
/** The {@code void} primitive type. Only used as a return type. */
public
static
final
TypeId
<
Void
>
VOID
=
new
TypeId
<>(
com
.
android
.
dx
.
rop
.
type
.
Type
.
VOID
);
/** The {@code Object} type. */
public
static
final
TypeId
<
Object
>
OBJECT
=
new
TypeId
<>(
com
.
android
.
dx
.
rop
.
type
.
Type
.
OBJECT
);
/** The {@code String} type. */
public
static
final
TypeId
<
String
>
STRING
=
new
TypeId
<>(
com
.
android
.
dx
.
rop
.
type
.
Type
.
STRING
);
private
static
final
Map
<
Class
<?>,
TypeId
<?>>
PRIMITIVE_TO_TYPE
=
new
HashMap
<>();
static
{
PRIMITIVE_TO_TYPE
.
put
(
boolean
.
class
,
BOOLEAN
);
PRIMITIVE_TO_TYPE
.
put
(
byte
.
class
,
BYTE
);
PRIMITIVE_TO_TYPE
.
put
(
char
.
class
,
CHAR
);
PRIMITIVE_TO_TYPE
.
put
(
double
.
class
,
DOUBLE
);
PRIMITIVE_TO_TYPE
.
put
(
float
.
class
,
FLOAT
);
PRIMITIVE_TO_TYPE
.
put
(
int
.
class
,
INT
);
PRIMITIVE_TO_TYPE
.
put
(
long
.
class
,
LONG
);
PRIMITIVE_TO_TYPE
.
put
(
short
.
class
,
SHORT
);
PRIMITIVE_TO_TYPE
.
put
(
void
.
class
,
VOID
);
}
final
String
name
;
/** cached converted values */
final
com
.
android
.
dx
.
rop
.
type
.
Type
ropType
;
final
CstType
constant
;
TypeId
(
com
.
android
.
dx
.
rop
.
type
.
Type
ropType
)
{
this
(
ropType
.
getDescriptor
(),
ropType
);
}
TypeId
(
String
name
,
com
.
android
.
dx
.
rop
.
type
.
Type
ropType
)
{
if
(
name
==
null
||
ropType
==
null
)
{
throw
new
NullPointerException
();
}
this
.
name
=
name
;
this
.
ropType
=
ropType
;
this
.
constant
=
CstType
.
intern
(
ropType
);
}
/**
* @param name a descriptor like "Ljava/lang/Class;".
*/
public
static
<
T
>
TypeId
<
T
>
get
(
String
name
)
{
return
new
TypeId
<>(
name
,
com
.
android
.
dx
.
rop
.
type
.
Type
.
internReturnType
(
name
));
}
public
static
<
T
>
TypeId
<
T
>
get
(
Class
<
T
>
type
)
{
if
(
type
.
isPrimitive
())
{
// guarded by equals
@SuppressWarnings
(
"unchecked"
)
TypeId
<
T
>
result
=
(
TypeId
<
T
>)
PRIMITIVE_TO_TYPE
.
get
(
type
);
return
result
;
}
String
name
=
type
.
getName
().
replace
(
'.'
,
'/'
);
return
get
(
type
.
isArray
()
?
name
:
'L'
+
name
+
';'
);
}
public
<
V
>
FieldId
<
T
,
V
>
getField
(
TypeId
<
V
>
type
,
String
name
)
{
return
new
FieldId
<>(
this
,
type
,
name
);
}
public
MethodId
<
T
,
Void
>
getConstructor
(
TypeId
<?>...
parameters
)
{
return
new
MethodId
<>(
this
,
VOID
,
"<init>"
,
new
TypeList
(
parameters
));
}
public
MethodId
<
T
,
Void
>
getStaticInitializer
()
{
return
new
MethodId
<>(
this
,
VOID
,
"<clinit>"
,
new
TypeList
(
new
TypeId
[
0
]));
}
public
<
R
>
MethodId
<
T
,
R
>
getMethod
(
TypeId
<
R
>
returnType
,
String
name
,
TypeId
<?>...
parameters
)
{
return
new
MethodId
<>(
this
,
returnType
,
name
,
new
TypeList
(
parameters
));
}
public
String
getName
()
{
return
name
;
}
@Override
public
boolean
equals
(
Object
o
)
{
return
o
instanceof
TypeId
&&
((
TypeId
)
o
).
name
.
equals
(
name
);
}
@Override
public
int
hashCode
()
{
return
name
.
hashCode
();
}
@Override
public
String
toString
()
{
return
name
;
}
}
xposedcompat/src/main/java/com/android/dx/TypeList.java
0 → 100755
View file @
5c250a7a
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
android
.
dx
;
import
com.android.dx.rop.type.StdTypeList
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.List
;
/**
* An immutable of types.
*/
final
class
TypeList
{
final
TypeId
<?>[]
types
;
final
StdTypeList
ropTypes
;
TypeList
(
TypeId
<?>[]
types
)
{
this
.
types
=
types
.
clone
();
this
.
ropTypes
=
new
StdTypeList
(
types
.
length
);
for
(
int
i
=
0
;
i
<
types
.
length
;
i
++)
{
ropTypes
.
set
(
i
,
types
[
i
].
ropType
);
}
}
/**
* Returns an immutable list.
*/
public
List
<
TypeId
<?>>
asList
()
{
return
Collections
.
unmodifiableList
(
Arrays
.
asList
(
types
));
}
@Override
public
boolean
equals
(
Object
o
)
{
return
o
instanceof
TypeList
&&
Arrays
.
equals
(((
TypeList
)
o
).
types
,
types
);
}
@Override
public
int
hashCode
()
{
return
Arrays
.
hashCode
(
types
);
}
@Override
public
String
toString
()
{
StringBuilder
result
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
types
.
length
;
i
++)
{
if
(
i
>
0
)
{
result
.
append
(
", "
);
}
result
.
append
(
types
[
i
]);
}
return
result
.
toString
();
}
}
xposedcompat/src/main/java/com/android/dx/UnaryOp.java
0 → 100755
View file @
5c250a7a
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
android
.
dx
;
import
com.android.dx.rop.code.Rop
;
import
com.android.dx.rop.code.Rops
;
/**
* An operation on one value.
*/
public
enum
UnaryOp
{
/** {@code ~a}. Supports int and long. */
NOT
()
{
@Override
Rop
rop
(
TypeId
<?>
type
)
{
return
Rops
.
opNot
(
type
.
ropType
);
}
},
/** {@code -a}. Supports int, long, float and double. */
NEGATE
()
{
@Override
Rop
rop
(
TypeId
<?>
type
)
{
return
Rops
.
opNeg
(
type
.
ropType
);
}
};
abstract
Rop
rop
(
TypeId
<?>
type
);
}
xposedcompat/src/main/java/com/android/dx/stock/ProxyBuilder.java
0 → 100755
View file @
5c250a7a
This diff is collapsed.
Click to expand it.
xposedcompat/src/main/java/com/swift/sandhook/xposedcompat/XposedCompat.java
View file @
5c250a7a
...
@@ -4,7 +4,7 @@ import android.app.Application;
...
@@ -4,7 +4,7 @@ import android.app.Application;
import
android.content.Context
;
import
android.content.Context
;
import
com.swift.sandhook.xposedcompat.classloaders.ComposeClassLoader
;
import
com.swift.sandhook.xposedcompat.classloaders.ComposeClassLoader
;
import
com.swift.sandhook.xposedcompat.
classloaders.XposedClassLoader
;
import
com.swift.sandhook.xposedcompat.
methodgen.DynamicBridge
;
import
com.swift.sandhook.xposedcompat.utils.ApplicationUtils
;
import
com.swift.sandhook.xposedcompat.utils.ApplicationUtils
;
import
com.swift.sandhook.xposedcompat.utils.ProcessUtils
;
import
com.swift.sandhook.xposedcompat.utils.ProcessUtils
;
...
@@ -73,4 +73,18 @@ public class XposedCompat {
...
@@ -73,4 +73,18 @@ public class XposedCompat {
}
}
}
}
public
static
boolean
clearCache
()
{
try
{
cacheDir
.
delete
();
cacheDir
.
mkdirs
();
return
true
;
}
catch
(
Throwable
throwable
)
{
return
false
;
}
}
public
static
void
clearOatCache
()
{
DynamicBridge
.
clearOatFile
();
}
}
}
xposedcompat/src/main/java/com/swift/sandhook/xposedcompat/methodgen/DynamicBridge.java
View file @
5c250a7a
package
com
.
swift
.
sandhook
.
xposedcompat
.
methodgen
;
package
com
.
swift
.
sandhook
.
xposedcompat
.
methodgen
;
import
android.os.Trace
;
import
com.swift.sandhook.xposedcompat.XposedCompat
;
import
com.swift.sandhook.xposedcompat.XposedCompat
;
import
com.swift.sandhook.xposedcompat.utils.DexLog
;
import
com.swift.sandhook.xposedcompat.utils.DexLog
;
import
com.swift.sandhook.xposedcompat.utils.FileUtils
;
import
java.io.File
;
import
java.io.File
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.Constructor
;
...
@@ -21,7 +22,6 @@ public final class DynamicBridge {
...
@@ -21,7 +22,6 @@ public final class DynamicBridge {
private
static
final
HookerDexMaker
dexMaker
=
new
HookerDexMaker
();
private
static
final
HookerDexMaker
dexMaker
=
new
HookerDexMaker
();
private
static
final
AtomicBoolean
dexPathInited
=
new
AtomicBoolean
(
false
);
private
static
final
AtomicBoolean
dexPathInited
=
new
AtomicBoolean
(
false
);
private
static
File
dexDir
;
private
static
File
dexDir
;
private
static
File
dexOptDir
;
public
static
void
onForkPost
()
{
public
static
void
onForkPost
()
{
dexPathInited
.
set
(
false
);
dexPathInited
.
set
(
false
);
...
@@ -45,28 +45,35 @@ public final class DynamicBridge {
...
@@ -45,28 +45,35 @@ public final class DynamicBridge {
// delete previous compiled dex to prevent potential crashing
// delete previous compiled dex to prevent potential crashing
// TODO find a way to reuse them in consideration of performance
// TODO find a way to reuse them in consideration of performance
try
{
try
{
// we always choose to use device encrypted storage data on android N and later
// in case some app is installing hooks before phone is unlocked
String
fixedAppDataDir
=
XposedCompat
.
cacheDir
.
getAbsolutePath
();
String
fixedAppDataDir
=
XposedCompat
.
cacheDir
.
getAbsolutePath
();
dexDir
=
new
File
(
fixedAppDataDir
,
"/sandxposed/"
);
dexDir
=
new
File
(
fixedAppDataDir
,
"/sandxposed/"
);
dexOptDir
=
new
File
(
dexDir
,
"oat"
);
dexDir
.
mkdirs
();
try
{
FileUtils
.
delete
(
dexOptDir
);
}
catch
(
Throwable
throwable
)
{
}
}
catch
(
Throwable
throwable
)
{
}
catch
(
Throwable
throwable
)
{
DexLog
.
e
(
"error when init dex path"
,
throwable
);
DexLog
.
e
(
"error when init dex path"
,
throwable
);
}
}
}
}
Trace
.
beginSection
(
"SandHook-Xposed"
);
long
timeStart
=
System
.
currentTimeMillis
();
dexMaker
.
start
(
hookMethod
,
additionalHookInfo
,
dexMaker
.
start
(
hookMethod
,
additionalHookInfo
,
XposedCompat
.
classLoader
,
dexDir
==
null
?
null
:
dexDir
.
getAbsolutePath
());
XposedCompat
.
classLoader
,
dexDir
==
null
?
null
:
dexDir
.
getAbsolutePath
());
DexLog
.
d
(
"hook method <"
+
hookMethod
.
toString
()
+
"> use "
+
(
System
.
currentTimeMillis
()
-
timeStart
)
+
" ms."
);
Trace
.
endSection
();
hookedInfo
.
put
(
hookMethod
,
dexMaker
.
getCallBackupMethod
());
hookedInfo
.
put
(
hookMethod
,
dexMaker
.
getCallBackupMethod
());
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
DexLog
.
e
(
"error occur when generating dex. dexDir="
+
dexDir
,
e
);
DexLog
.
e
(
"error occur when generating dex. dexDir="
+
dexDir
,
e
);
}
}
}
}
public
static
void
clearOatFile
()
{
String
fixedAppDataDir
=
XposedCompat
.
cacheDir
.
getAbsolutePath
();
File
dexOatDir
=
new
File
(
fixedAppDataDir
,
"/sandxposed/oat/"
);
if
(!
dexOatDir
.
exists
())
return
;
try
{
dexOatDir
.
delete
();
}
catch
(
Throwable
throwable
)
{
}
}
private
static
boolean
checkMember
(
Member
member
)
{
private
static
boolean
checkMember
(
Member
member
)
{
if
(
member
instanceof
Method
)
{
if
(
member
instanceof
Method
)
{
...
...
xposedcompat/src/main/java/com/swift/sandhook/xposedcompat/methodgen/HookerDexMaker.java
View file @
5c250a7a
...
@@ -25,6 +25,7 @@ import java.util.concurrent.atomic.AtomicLong;
...
@@ -25,6 +25,7 @@ import java.util.concurrent.atomic.AtomicLong;
import
de.robv.android.xposed.XC_MethodHook
;
import
de.robv.android.xposed.XC_MethodHook
;
import
de.robv.android.xposed.XposedBridge
;
import
de.robv.android.xposed.XposedBridge
;
import
static
com
.
swift
.
sandhook
.
xposedcompat
.
utils
.
DexMakerUtils
.
MD5
;
import
static
com
.
swift
.
sandhook
.
xposedcompat
.
utils
.
DexMakerUtils
.
autoBoxIfNecessary
;
import
static
com
.
swift
.
sandhook
.
xposedcompat
.
utils
.
DexMakerUtils
.
autoBoxIfNecessary
;
import
static
com
.
swift
.
sandhook
.
xposedcompat
.
utils
.
DexMakerUtils
.
autoUnboxIfNecessary
;
import
static
com
.
swift
.
sandhook
.
xposedcompat
.
utils
.
DexMakerUtils
.
autoUnboxIfNecessary
;
import
static
com
.
swift
.
sandhook
.
xposedcompat
.
utils
.
DexMakerUtils
.
createResultLocals
;
import
static
com
.
swift
.
sandhook
.
xposedcompat
.
utils
.
DexMakerUtils
.
createResultLocals
;
...
@@ -79,8 +80,6 @@ public class HookerDexMaker {
...
@@ -79,8 +80,6 @@ public class HookerDexMaker {
private
static
final
MethodId
<
XposedBridge
,
Void
>
logStrMethodId
=
private
static
final
MethodId
<
XposedBridge
,
Void
>
logStrMethodId
=
xposedBridgeTypeId
.
getMethod
(
TypeId
.
VOID
,
"log"
,
TypeId
.
STRING
);
xposedBridgeTypeId
.
getMethod
(
TypeId
.
VOID
,
"log"
,
TypeId
.
STRING
);
private
static
AtomicLong
sClassNameSuffix
=
new
AtomicLong
(
1
);
private
FieldId
<?,
XposedBridge
.
AdditionalHookInfo
>
mHookInfoFieldId
;
private
FieldId
<?,
XposedBridge
.
AdditionalHookInfo
>
mHookInfoFieldId
;
private
FieldId
<?,
Member
>
mMethodFieldId
;
private
FieldId
<?,
Member
>
mMethodFieldId
;
private
MethodId
<?,
?>
mBackupMethodId
;
private
MethodId
<?,
?>
mBackupMethodId
;
...
@@ -175,15 +174,30 @@ public class HookerDexMaker {
...
@@ -175,15 +174,30 @@ public class HookerDexMaker {
}
else
{
}
else
{
mAppClassLoader
=
appClassLoader
;
mAppClassLoader
=
appClassLoader
;
}
}
doMake
();
}
private
void
doMake
()
throws
Exception
{
mDexMaker
=
new
DexMaker
();
mDexMaker
=
new
DexMaker
();
// Generate a Hooker class.
// Generate a Hooker class.
String
className
=
CLASS_NAME_PREFIX
+
sClassNameSuffix
.
getAndIncrement
();
String
className
=
getClassName
(
mMember
);
String
classDesc
=
CLASS_DESC_PREFIX
+
className
+
";"
;
String
dexName
=
className
+
".jar"
;
mHookerTypeId
=
TypeId
.
get
(
classDesc
);
HookWrapper
.
HookEntity
hookEntity
=
null
;
//try load cache first
try
{
ClassLoader
loader
=
mDexMaker
.
loadClassDirect
(
mAppClassLoader
,
new
File
(
mDexDirPath
),
dexName
);
if
(
loader
!=
null
)
{
hookEntity
=
loadHookerClass
(
loader
,
className
);
}
}
catch
(
Throwable
throwable
)
{}
//do generate
if
(
hookEntity
==
null
)
{
hookEntity
=
doMake
(
className
,
dexName
);
}
SandHook
.
hook
(
hookEntity
);
}
private
HookWrapper
.
HookEntity
doMake
(
String
className
,
String
dexName
)
throws
Exception
{
mHookerTypeId
=
TypeId
.
get
(
CLASS_DESC_PREFIX
+
className
+
";"
);
mDexMaker
.
declare
(
mHookerTypeId
,
className
+
".generated"
,
Modifier
.
PUBLIC
,
TypeId
.
OBJECT
);
mDexMaker
.
declare
(
mHookerTypeId
,
className
+
".generated"
,
Modifier
.
PUBLIC
,
TypeId
.
OBJECT
);
generateFields
();
generateFields
();
generateSetupMethod
();
generateSetupMethod
();
...
@@ -195,9 +209,12 @@ public class HookerDexMaker {
...
@@ -195,9 +209,12 @@ public class HookerDexMaker {
if
(
TextUtils
.
isEmpty
(
mDexDirPath
))
{
if
(
TextUtils
.
isEmpty
(
mDexDirPath
))
{
throw
new
IllegalArgumentException
(
"dexDirPath should not be empty!!!"
);
throw
new
IllegalArgumentException
(
"dexDirPath should not be empty!!!"
);
}
}
// Create the dex file and load it.
// Create the dex file and load it.
loader
=
mDexMaker
.
generateAndLoad
(
mAppClassLoader
,
new
File
(
mDexDirPath
));
loader
=
mDexMaker
.
generateAndLoad
(
mAppClassLoader
,
new
File
(
mDexDirPath
),
dexName
);
return
loadHookerClass
(
loader
,
className
);
}
private
HookWrapper
.
HookEntity
loadHookerClass
(
ClassLoader
loader
,
String
className
)
throws
Exception
{
mHookClass
=
loader
.
loadClass
(
className
);
mHookClass
=
loader
.
loadClass
(
className
);
// Execute our newly-generated code in-process.
// Execute our newly-generated code in-process.
mHookClass
.
getMethod
(
METHOD_NAME_SETUP
,
Member
.
class
,
XposedBridge
.
AdditionalHookInfo
.
class
)
mHookClass
.
getMethod
(
METHOD_NAME_SETUP
,
Member
.
class
,
XposedBridge
.
AdditionalHookInfo
.
class
)
...
@@ -205,7 +222,11 @@ public class HookerDexMaker {
...
@@ -205,7 +222,11 @@ public class HookerDexMaker {
mHookMethod
=
mHookClass
.
getMethod
(
METHOD_NAME_HOOK
,
mActualParameterTypes
);
mHookMethod
=
mHookClass
.
getMethod
(
METHOD_NAME_HOOK
,
mActualParameterTypes
);
mBackupMethod
=
mHookClass
.
getMethod
(
METHOD_NAME_BACKUP
,
mActualParameterTypes
);
mBackupMethod
=
mHookClass
.
getMethod
(
METHOD_NAME_BACKUP
,
mActualParameterTypes
);
mCallBackupMethod
=
mHookClass
.
getMethod
(
METHOD_NAME_CALL_BACKUP
,
mActualParameterTypes
);
mCallBackupMethod
=
mHookClass
.
getMethod
(
METHOD_NAME_CALL_BACKUP
,
mActualParameterTypes
);
SandHook
.
hook
(
new
HookWrapper
.
HookEntity
(
mMember
,
mHookMethod
,
mBackupMethod
));
return
new
HookWrapper
.
HookEntity
(
mMember
,
mHookMethod
,
mBackupMethod
);
}
private
String
getClassName
(
Member
originMethod
)
{
return
CLASS_NAME_PREFIX
+
"_"
+
originMethod
.
getName
()
+
"_"
+
MD5
(
originMethod
.
toString
());
}
}
public
Method
getHookMethod
()
{
public
Method
getHookMethod
()
{
...
...
xposedcompat/src/main/java/com/swift/sandhook/xposedcompat/utils/DexMakerUtils.java
View file @
5c250a7a
...
@@ -12,6 +12,9 @@ import com.android.dx.rop.type.Type;
...
@@ -12,6 +12,9 @@ import com.android.dx.rop.type.Type;
import
java.lang.reflect.InvocationTargetException
;
import
java.lang.reflect.InvocationTargetException
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Method
;
import
java.math.BigInteger
;
import
java.security.MessageDigest
;
import
java.security.NoSuchAlgorithmException
;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.Map
;
...
@@ -253,4 +256,15 @@ public class DexMakerUtils {
...
@@ -253,4 +256,15 @@ public class DexMakerUtils {
return
null
;
return
null
;
}
}
}
}
public
static
String
MD5
(
String
source
)
{
try
{
MessageDigest
messageDigest
=
MessageDigest
.
getInstance
(
"MD5"
);
messageDigest
.
update
(
source
.
getBytes
());
return
new
BigInteger
(
1
,
messageDigest
.
digest
()).
toString
(
32
);
}
catch
(
NoSuchAlgorithmException
e
)
{
e
.
printStackTrace
();
}
return
source
;
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment