frida-java-bridge 5.3.0 → 6.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/android.js +497 -69
- package/lib/class-factory.js +4 -0
- package/lib/vm.js +58 -17
- package/package.json +1 -1
package/lib/android.js
CHANGED
|
@@ -105,6 +105,7 @@ let thunkPage = null;
|
|
|
105
105
|
let thunkOffset = 0;
|
|
106
106
|
let taughtArtAboutReplacementMethods = false;
|
|
107
107
|
let taughtArtAboutMethodInstrumentation = false;
|
|
108
|
+
let backtraceModule = null;
|
|
108
109
|
const jdwpSessions = [];
|
|
109
110
|
let socketpair = null;
|
|
110
111
|
|
|
@@ -1199,6 +1200,11 @@ function withRunnableArtThread (vm, env, fn) {
|
|
|
1199
1200
|
}
|
|
1200
1201
|
}
|
|
1201
1202
|
|
|
1203
|
+
function _getArtThreadStateTransitionImpl (vm, env) {
|
|
1204
|
+
const callback = new NativeCallback(onThreadStateTransitionComplete, 'void', ['pointer']);
|
|
1205
|
+
return makeArtThreadStateTransitionImpl(vm, env, callback);
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1202
1208
|
function onThreadStateTransitionComplete (thread) {
|
|
1203
1209
|
const id = thread.toString();
|
|
1204
1210
|
|
|
@@ -1815,87 +1821,510 @@ function translateMethod (methodId) {
|
|
|
1815
1821
|
return artController.replacedMethods.translate(methodId);
|
|
1816
1822
|
}
|
|
1817
1823
|
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
const api = getApi();
|
|
1821
|
-
|
|
1822
|
-
super(thread, api['art::Thread::GetLongJumpContext'](thread), 'include-inlined-frames');
|
|
1824
|
+
function backtrace (vm, options = {}) {
|
|
1825
|
+
const { limit = 16 } = options;
|
|
1823
1826
|
|
|
1824
|
-
|
|
1825
|
-
this.limit = limit;
|
|
1827
|
+
const env = vm.getEnv();
|
|
1826
1828
|
|
|
1827
|
-
|
|
1829
|
+
if (backtraceModule === null) {
|
|
1830
|
+
backtraceModule = makeBacktraceModule(vm, env);
|
|
1828
1831
|
}
|
|
1829
1832
|
|
|
1830
|
-
|
|
1831
|
-
|
|
1833
|
+
return backtraceModule.backtrace(env, limit);
|
|
1834
|
+
}
|
|
1832
1835
|
|
|
1833
|
-
|
|
1834
|
-
|
|
1836
|
+
function makeBacktraceModule (vm, env) {
|
|
1837
|
+
const api = getApi();
|
|
1835
1838
|
|
|
1836
|
-
|
|
1837
|
-
if (location === 'upcall') {
|
|
1838
|
-
return;
|
|
1839
|
-
}
|
|
1839
|
+
const performImpl = Memory.alloc(Process.pointerSize);
|
|
1840
1840
|
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1841
|
+
const cm = new CModule(`
|
|
1842
|
+
#include <glib.h>
|
|
1843
|
+
#include <stdbool.h>
|
|
1844
|
+
#include <string.h>
|
|
1845
|
+
#include <gum/gumtls.h>
|
|
1846
|
+
#include <json-glib/json-glib.h>
|
|
1847
|
+
|
|
1848
|
+
typedef struct _ArtBacktrace ArtBacktrace;
|
|
1849
|
+
typedef struct _ArtStackFrame ArtStackFrame;
|
|
1850
|
+
|
|
1851
|
+
typedef struct _ArtStackVisitor ArtStackVisitor;
|
|
1852
|
+
typedef struct _ArtStackVisitorVTable ArtStackVisitorVTable;
|
|
1853
|
+
|
|
1854
|
+
typedef struct _ArtMethod ArtMethod;
|
|
1855
|
+
typedef struct _ArtThread ArtThread;
|
|
1856
|
+
typedef struct _ArtContext ArtContext;
|
|
1857
|
+
|
|
1858
|
+
typedef struct _JNIEnv JNIEnv;
|
|
1859
|
+
|
|
1860
|
+
typedef struct _StdString StdString;
|
|
1861
|
+
typedef struct _StdTinyString StdTinyString;
|
|
1862
|
+
typedef struct _StdLargeString StdLargeString;
|
|
1863
|
+
|
|
1864
|
+
typedef enum {
|
|
1865
|
+
STACK_WALK_INCLUDE_INLINED_FRAMES,
|
|
1866
|
+
STACK_WALK_SKIP_INLINED_FRAMES,
|
|
1867
|
+
} StackWalkKind;
|
|
1868
|
+
|
|
1869
|
+
struct _StdTinyString
|
|
1870
|
+
{
|
|
1871
|
+
guint8 unused;
|
|
1872
|
+
gchar data[(3 * sizeof (gpointer)) - 1];
|
|
1873
|
+
};
|
|
1874
|
+
|
|
1875
|
+
struct _StdLargeString
|
|
1876
|
+
{
|
|
1877
|
+
gsize capacity;
|
|
1878
|
+
gsize size;
|
|
1879
|
+
gchar * data;
|
|
1880
|
+
};
|
|
1881
|
+
|
|
1882
|
+
struct _StdString
|
|
1883
|
+
{
|
|
1884
|
+
union
|
|
1885
|
+
{
|
|
1886
|
+
guint8 flags;
|
|
1887
|
+
StdTinyString tiny;
|
|
1888
|
+
StdLargeString large;
|
|
1889
|
+
};
|
|
1890
|
+
};
|
|
1891
|
+
|
|
1892
|
+
struct _ArtBacktrace
|
|
1893
|
+
{
|
|
1894
|
+
GChecksum * id;
|
|
1895
|
+
GArray * frames;
|
|
1896
|
+
gchar * frames_json;
|
|
1897
|
+
};
|
|
1898
|
+
|
|
1899
|
+
struct _ArtStackFrame
|
|
1900
|
+
{
|
|
1901
|
+
ArtMethod * method;
|
|
1902
|
+
gsize dexpc;
|
|
1903
|
+
StdString description;
|
|
1904
|
+
};
|
|
1905
|
+
|
|
1906
|
+
struct _ArtStackVisitorVTable
|
|
1907
|
+
{
|
|
1908
|
+
void (* unused1) (void);
|
|
1909
|
+
void (* unused2) (void);
|
|
1910
|
+
bool (* visit) (ArtStackVisitor * visitor);
|
|
1911
|
+
};
|
|
1912
|
+
|
|
1913
|
+
struct _ArtStackVisitor
|
|
1914
|
+
{
|
|
1915
|
+
ArtStackVisitorVTable * vtable;
|
|
1916
|
+
|
|
1917
|
+
guint8 padding[512];
|
|
1918
|
+
|
|
1919
|
+
ArtStackVisitorVTable vtable_storage;
|
|
1920
|
+
|
|
1921
|
+
ArtBacktrace * backtrace;
|
|
1922
|
+
};
|
|
1923
|
+
|
|
1924
|
+
extern GumTlsKey current_backtrace;
|
|
1925
|
+
|
|
1926
|
+
extern void (* perform_art_thread_state_transition) (JNIEnv * env);
|
|
1927
|
+
|
|
1928
|
+
extern ArtContext * art_thread_get_long_jump_context (ArtThread * thread);
|
|
1929
|
+
|
|
1930
|
+
extern void art_stack_visitor_init (ArtStackVisitor * visitor, ArtThread * thread, void * context, StackWalkKind walk_kind,
|
|
1931
|
+
size_t num_frames, bool check_suspended);
|
|
1932
|
+
extern void art_stack_visitor_walk_stack (ArtStackVisitor * visitor, bool include_transitions);
|
|
1933
|
+
extern ArtMethod * art_stack_visitor_get_method (ArtStackVisitor * visitor);
|
|
1934
|
+
extern void art_stack_visitor_describe_location (StdString * description, ArtStackVisitor * visitor);
|
|
1935
|
+
extern ArtMethod * translate_method (ArtMethod * method);
|
|
1936
|
+
extern void translate_location (ArtMethod * method, guint32 pc, const gchar ** source_file, gint32 * line_number);
|
|
1937
|
+
extern void cxx_delete (void * mem);
|
|
1938
|
+
extern unsigned long strtoul (const char * str, char ** endptr, int base);
|
|
1939
|
+
|
|
1940
|
+
extern void _frida_log (const gchar * message);
|
|
1941
|
+
|
|
1942
|
+
static bool visit_frame (ArtStackVisitor * visitor);
|
|
1943
|
+
static void art_stack_frame_destroy (ArtStackFrame * frame);
|
|
1944
|
+
|
|
1945
|
+
static void append_jni_type_name (GString * s, const gchar * name, gsize length);
|
|
1946
|
+
|
|
1947
|
+
static void std_string_destroy (StdString * str);
|
|
1948
|
+
static gchar * std_string_get_data (StdString * str);
|
|
1949
|
+
|
|
1950
|
+
static void frida_log (const char * format, ...);
|
|
1951
|
+
|
|
1952
|
+
void
|
|
1953
|
+
init (void)
|
|
1954
|
+
{
|
|
1955
|
+
current_backtrace = gum_tls_key_new ();
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
void
|
|
1959
|
+
finalize (void)
|
|
1960
|
+
{
|
|
1961
|
+
gum_tls_key_free (current_backtrace);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
ArtBacktrace *
|
|
1965
|
+
_create (JNIEnv * env,
|
|
1966
|
+
guint limit)
|
|
1967
|
+
{
|
|
1968
|
+
ArtBacktrace * bt;
|
|
1969
|
+
|
|
1970
|
+
bt = g_new (ArtBacktrace, 1);
|
|
1971
|
+
bt->id = g_checksum_new (G_CHECKSUM_SHA1);
|
|
1972
|
+
bt->frames = (limit != 0)
|
|
1973
|
+
? g_array_sized_new (FALSE, FALSE, sizeof (ArtStackFrame), limit)
|
|
1974
|
+
: g_array_new (FALSE, FALSE, sizeof (ArtStackFrame));
|
|
1975
|
+
g_array_set_clear_func (bt->frames, (GDestroyNotify) art_stack_frame_destroy);
|
|
1976
|
+
bt->frames_json = NULL;
|
|
1977
|
+
|
|
1978
|
+
gum_tls_key_set_value (current_backtrace, bt);
|
|
1979
|
+
|
|
1980
|
+
perform_art_thread_state_transition (env);
|
|
1981
|
+
|
|
1982
|
+
gum_tls_key_set_value (current_backtrace, NULL);
|
|
1983
|
+
|
|
1984
|
+
return bt;
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
void
|
|
1988
|
+
_on_thread_state_transition_complete (ArtThread * thread)
|
|
1989
|
+
{
|
|
1990
|
+
ArtContext * context;
|
|
1991
|
+
ArtStackVisitor visitor = {
|
|
1992
|
+
.vtable_storage = {
|
|
1993
|
+
.visit = visit_frame,
|
|
1994
|
+
},
|
|
1995
|
+
};
|
|
1996
|
+
|
|
1997
|
+
context = art_thread_get_long_jump_context (thread);
|
|
1998
|
+
|
|
1999
|
+
art_stack_visitor_init (&visitor, thread, context, STACK_WALK_SKIP_INLINED_FRAMES, 0, true);
|
|
2000
|
+
visitor.vtable = &visitor.vtable_storage;
|
|
2001
|
+
visitor.backtrace = gum_tls_key_get_value (current_backtrace);
|
|
2002
|
+
|
|
2003
|
+
art_stack_visitor_walk_stack (&visitor, false);
|
|
2004
|
+
|
|
2005
|
+
cxx_delete (context);
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
static bool
|
|
2009
|
+
visit_frame (ArtStackVisitor * visitor)
|
|
2010
|
+
{
|
|
2011
|
+
ArtBacktrace * bt = visitor->backtrace;
|
|
2012
|
+
ArtStackFrame frame;
|
|
2013
|
+
const gchar * description, * dexpc_part;
|
|
2014
|
+
|
|
2015
|
+
frame.method = art_stack_visitor_get_method (visitor);
|
|
2016
|
+
|
|
2017
|
+
art_stack_visitor_describe_location (&frame.description, visitor);
|
|
2018
|
+
|
|
2019
|
+
description = std_string_get_data (&frame.description);
|
|
2020
|
+
if (strstr (description, " '<") != NULL)
|
|
2021
|
+
goto skip;
|
|
2022
|
+
|
|
2023
|
+
dexpc_part = strstr (description, " at dex PC 0x");
|
|
2024
|
+
if (dexpc_part == NULL)
|
|
2025
|
+
goto skip;
|
|
2026
|
+
frame.dexpc = strtoul (dexpc_part + 13, NULL, 16);
|
|
2027
|
+
|
|
2028
|
+
g_array_append_val (bt->frames, frame);
|
|
2029
|
+
|
|
2030
|
+
g_checksum_update (bt->id, (guchar *) &frame.method, sizeof (frame.method));
|
|
2031
|
+
g_checksum_update (bt->id, (guchar *) &frame.dexpc, sizeof (frame.dexpc));
|
|
2032
|
+
|
|
2033
|
+
return true;
|
|
2034
|
+
|
|
2035
|
+
skip:
|
|
2036
|
+
std_string_destroy (&frame.description);
|
|
2037
|
+
return true;
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
static void
|
|
2041
|
+
art_stack_frame_destroy (ArtStackFrame * frame)
|
|
2042
|
+
{
|
|
2043
|
+
std_string_destroy (&frame->description);
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
void
|
|
2047
|
+
_destroy (ArtBacktrace * backtrace)
|
|
2048
|
+
{
|
|
2049
|
+
g_free (backtrace->frames_json);
|
|
2050
|
+
g_array_free (backtrace->frames, TRUE);
|
|
2051
|
+
g_checksum_free (backtrace->id);
|
|
2052
|
+
g_free (backtrace);
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
const gchar *
|
|
2056
|
+
_get_id (ArtBacktrace * backtrace)
|
|
2057
|
+
{
|
|
2058
|
+
return g_checksum_get_string (backtrace->id);
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
const gchar *
|
|
2062
|
+
_get_frames (ArtBacktrace * backtrace)
|
|
2063
|
+
{
|
|
2064
|
+
GArray * frames = backtrace->frames;
|
|
2065
|
+
JsonBuilder * b;
|
|
2066
|
+
guint i;
|
|
2067
|
+
JsonNode * root;
|
|
2068
|
+
|
|
2069
|
+
if (backtrace->frames_json != NULL)
|
|
2070
|
+
return backtrace->frames_json;
|
|
2071
|
+
|
|
2072
|
+
b = json_builder_new_immutable ();
|
|
2073
|
+
|
|
2074
|
+
json_builder_begin_array (b);
|
|
2075
|
+
|
|
2076
|
+
for (i = 0; i != frames->len; i++)
|
|
2077
|
+
{
|
|
2078
|
+
ArtStackFrame * frame = &g_array_index (frames, ArtStackFrame, i);
|
|
2079
|
+
gchar * description, * ret_type, * paren_open, * paren_close, * arg_types, * token, * method_name, * class_name;
|
|
2080
|
+
GString * signature;
|
|
2081
|
+
gchar * cursor;
|
|
2082
|
+
ArtMethod * translated_method;
|
|
2083
|
+
gsize dexpc;
|
|
2084
|
+
const gchar * source_file;
|
|
2085
|
+
gint32 line_number;
|
|
2086
|
+
|
|
2087
|
+
description = std_string_get_data (&frame->description);
|
|
2088
|
+
|
|
2089
|
+
ret_type = strchr (description, '\\'') + 1;
|
|
2090
|
+
|
|
2091
|
+
paren_open = strchr (ret_type, '(');
|
|
2092
|
+
paren_close = strchr (paren_open, ')');
|
|
2093
|
+
*paren_open = '\\0';
|
|
2094
|
+
*paren_close = '\\0';
|
|
2095
|
+
|
|
2096
|
+
arg_types = paren_open + 1;
|
|
2097
|
+
|
|
2098
|
+
token = strrchr (ret_type, '.');
|
|
2099
|
+
*token = '\\0';
|
|
2100
|
+
|
|
2101
|
+
method_name = token + 1;
|
|
2102
|
+
|
|
2103
|
+
token = strrchr (ret_type, ' ');
|
|
2104
|
+
*token = '\\0';
|
|
2105
|
+
|
|
2106
|
+
class_name = token + 1;
|
|
2107
|
+
|
|
2108
|
+
signature = g_string_sized_new (128);
|
|
2109
|
+
|
|
2110
|
+
append_jni_type_name (signature, class_name, method_name - class_name - 1);
|
|
2111
|
+
g_string_append_c (signature, ',');
|
|
2112
|
+
g_string_append (signature, method_name);
|
|
2113
|
+
g_string_append (signature, ",(");
|
|
2114
|
+
|
|
2115
|
+
if (arg_types != paren_close)
|
|
2116
|
+
{
|
|
2117
|
+
for (cursor = arg_types; cursor != NULL;)
|
|
2118
|
+
{
|
|
2119
|
+
gsize length;
|
|
2120
|
+
gchar * next;
|
|
2121
|
+
|
|
2122
|
+
token = strstr (cursor, ", ");
|
|
2123
|
+
if (token != NULL)
|
|
2124
|
+
{
|
|
2125
|
+
length = token - cursor;
|
|
2126
|
+
next = token + 2;
|
|
2127
|
+
}
|
|
2128
|
+
else
|
|
2129
|
+
{
|
|
2130
|
+
length = paren_close - cursor;
|
|
2131
|
+
next = NULL;
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
append_jni_type_name (signature, cursor, length);
|
|
2135
|
+
|
|
2136
|
+
cursor = next;
|
|
2137
|
+
}
|
|
1866
2138
|
}
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
2139
|
+
|
|
2140
|
+
g_string_append_c (signature, ')');
|
|
2141
|
+
|
|
2142
|
+
append_jni_type_name (signature, ret_type, class_name - ret_type - 1);
|
|
2143
|
+
|
|
2144
|
+
translated_method = translate_method (frame->method);
|
|
2145
|
+
dexpc = (translated_method == frame->method) ? frame->dexpc : 0;
|
|
2146
|
+
|
|
2147
|
+
translate_location (translated_method, dexpc, &source_file, &line_number);
|
|
2148
|
+
|
|
2149
|
+
json_builder_begin_object (b);
|
|
2150
|
+
|
|
2151
|
+
json_builder_set_member_name (b, "signature");
|
|
2152
|
+
json_builder_add_string_value (b, signature->str);
|
|
2153
|
+
|
|
2154
|
+
json_builder_set_member_name (b, "className");
|
|
2155
|
+
json_builder_add_string_value (b, class_name);
|
|
2156
|
+
|
|
2157
|
+
json_builder_set_member_name (b, "methodName");
|
|
2158
|
+
json_builder_add_string_value (b, method_name);
|
|
2159
|
+
|
|
2160
|
+
json_builder_set_member_name (b, "fileName");
|
|
2161
|
+
json_builder_add_string_value (b, source_file);
|
|
2162
|
+
|
|
2163
|
+
json_builder_set_member_name (b, "lineNumber");
|
|
2164
|
+
json_builder_add_int_value (b, line_number);
|
|
2165
|
+
|
|
2166
|
+
json_builder_end_object (b);
|
|
2167
|
+
|
|
2168
|
+
g_string_free (signature, TRUE);
|
|
1884
2169
|
}
|
|
2170
|
+
|
|
2171
|
+
json_builder_end_array (b);
|
|
2172
|
+
|
|
2173
|
+
root = json_builder_get_root (b);
|
|
2174
|
+
backtrace->frames_json = json_to_string (root, FALSE);
|
|
2175
|
+
json_node_unref (root);
|
|
2176
|
+
|
|
2177
|
+
return backtrace->frames_json;
|
|
1885
2178
|
}
|
|
1886
2179
|
|
|
1887
|
-
|
|
1888
|
-
|
|
2180
|
+
static void
|
|
2181
|
+
append_jni_type_name (GString * s,
|
|
2182
|
+
const gchar * name,
|
|
2183
|
+
gsize length)
|
|
2184
|
+
{
|
|
2185
|
+
gchar shorty = '\\0';
|
|
2186
|
+
gsize i;
|
|
1889
2187
|
|
|
1890
|
-
|
|
2188
|
+
switch (name[0])
|
|
2189
|
+
{
|
|
2190
|
+
case 'b':
|
|
2191
|
+
if (strncmp (name, "boolean", length) == 0)
|
|
2192
|
+
shorty = 'Z';
|
|
2193
|
+
else if (strncmp (name, "byte", length) == 0)
|
|
2194
|
+
shorty = 'B';
|
|
2195
|
+
break;
|
|
2196
|
+
case 'c':
|
|
2197
|
+
if (strncmp (name, "char", length) == 0)
|
|
2198
|
+
shorty = 'C';
|
|
2199
|
+
break;
|
|
2200
|
+
case 'd':
|
|
2201
|
+
if (strncmp (name, "double", length) == 0)
|
|
2202
|
+
shorty = 'D';
|
|
2203
|
+
break;
|
|
2204
|
+
case 'f':
|
|
2205
|
+
if (strncmp (name, "float", length) == 0)
|
|
2206
|
+
shorty = 'F';
|
|
2207
|
+
break;
|
|
2208
|
+
case 'i':
|
|
2209
|
+
if (strncmp (name, "int", length) == 0)
|
|
2210
|
+
shorty = 'I';
|
|
2211
|
+
break;
|
|
2212
|
+
case 'l':
|
|
2213
|
+
if (strncmp (name, "long", length) == 0)
|
|
2214
|
+
shorty = 'J';
|
|
2215
|
+
break;
|
|
2216
|
+
case 's':
|
|
2217
|
+
if (strncmp (name, "short", length) == 0)
|
|
2218
|
+
shorty = 'S';
|
|
2219
|
+
break;
|
|
2220
|
+
case 'v':
|
|
2221
|
+
if (strncmp (name, "void", length) == 0)
|
|
2222
|
+
shorty = 'V';
|
|
2223
|
+
break;
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
if (shorty != '\\0')
|
|
2227
|
+
{
|
|
2228
|
+
g_string_append_c (s, shorty);
|
|
2229
|
+
|
|
2230
|
+
return;
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
if (length > 2 && name[length - 2] == '[' && name[length - 1] == ']')
|
|
2234
|
+
{
|
|
2235
|
+
g_string_append_c (s, '[');
|
|
2236
|
+
append_jni_type_name (s, name, length - 2);
|
|
2237
|
+
|
|
2238
|
+
return;
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
g_string_append_c (s, 'L');
|
|
2242
|
+
|
|
2243
|
+
for (i = 0; i != length; i++)
|
|
2244
|
+
{
|
|
2245
|
+
gchar ch = name[i];
|
|
2246
|
+
if (ch != '.')
|
|
2247
|
+
g_string_append_c (s, ch);
|
|
2248
|
+
else
|
|
2249
|
+
g_string_append_c (s, '/');
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
g_string_append_c (s, ';');
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
static void
|
|
2256
|
+
std_string_destroy (StdString * str)
|
|
2257
|
+
{
|
|
2258
|
+
bool is_large = (str->flags & 1) != 0;
|
|
2259
|
+
if (is_large)
|
|
2260
|
+
cxx_delete (str->large.data);
|
|
2261
|
+
}
|
|
1891
2262
|
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
2263
|
+
static gchar *
|
|
2264
|
+
std_string_get_data (StdString * str)
|
|
2265
|
+
{
|
|
2266
|
+
bool is_large = (str->flags & 1) != 0;
|
|
2267
|
+
return is_large ? str->large.data : str->tiny.data;
|
|
2268
|
+
}
|
|
2269
|
+
`, {
|
|
2270
|
+
current_backtrace: Memory.alloc(Process.pointerSize),
|
|
2271
|
+
perform_art_thread_state_transition: performImpl,
|
|
2272
|
+
art_thread_get_long_jump_context: api['art::Thread::GetLongJumpContext'],
|
|
2273
|
+
art_stack_visitor_init: api['art::StackVisitor::StackVisitor'],
|
|
2274
|
+
art_stack_visitor_walk_stack: api['art::StackVisitor::WalkStack'],
|
|
2275
|
+
art_stack_visitor_get_method: api['art::StackVisitor::GetMethod'],
|
|
2276
|
+
art_stack_visitor_describe_location: api['art::StackVisitor::DescribeLocation'],
|
|
2277
|
+
translate_method: artController.replacedMethods.translate,
|
|
2278
|
+
translate_location: api['art::Monitor::TranslateLocation'],
|
|
2279
|
+
cxx_delete: api.$delete,
|
|
2280
|
+
strtoul: Module.getExportByName('libc.so', 'strtoul')
|
|
1896
2281
|
});
|
|
1897
2282
|
|
|
1898
|
-
|
|
2283
|
+
const _create = new NativeFunction(cm._create, 'pointer', ['pointer', 'uint'], nativeFunctionOptions);
|
|
2284
|
+
const _destroy = new NativeFunction(cm._destroy, 'void', ['pointer'], nativeFunctionOptions);
|
|
2285
|
+
|
|
2286
|
+
const fastOptions = { exceptions: 'propagate', scheduling: 'exclusive' };
|
|
2287
|
+
const _getId = new NativeFunction(cm._get_id, 'pointer', ['pointer'], fastOptions);
|
|
2288
|
+
const _getFrames = new NativeFunction(cm._get_frames, 'pointer', ['pointer'], fastOptions);
|
|
2289
|
+
|
|
2290
|
+
const performThreadStateTransition = makeArtThreadStateTransitionImpl(vm, env, cm._on_thread_state_transition_complete);
|
|
2291
|
+
cm._performData = performThreadStateTransition;
|
|
2292
|
+
performImpl.writePointer(performThreadStateTransition);
|
|
2293
|
+
|
|
2294
|
+
cm.backtrace = (env, limit) => {
|
|
2295
|
+
const handle = _create(env, limit);
|
|
2296
|
+
const bt = new Backtrace(handle);
|
|
2297
|
+
Script.bindWeak(bt, destroy.bind(null, handle));
|
|
2298
|
+
return bt;
|
|
2299
|
+
};
|
|
2300
|
+
|
|
2301
|
+
function destroy (handle) {
|
|
2302
|
+
_destroy(handle);
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
cm.getId = handle => {
|
|
2306
|
+
return _getId(handle).readUtf8String();
|
|
2307
|
+
};
|
|
2308
|
+
|
|
2309
|
+
cm.getFrames = handle => {
|
|
2310
|
+
return JSON.parse(_getFrames(handle).readUtf8String());
|
|
2311
|
+
};
|
|
2312
|
+
|
|
2313
|
+
return cm;
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
class Backtrace {
|
|
2317
|
+
constructor (handle) {
|
|
2318
|
+
this.handle = handle;
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
get id () {
|
|
2322
|
+
return backtraceModule.getId(this.handle);
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
get frames () {
|
|
2326
|
+
return backtraceModule.getFrames(this.handle);
|
|
2327
|
+
}
|
|
1899
2328
|
}
|
|
1900
2329
|
|
|
1901
2330
|
function revertGlobalPatches () {
|
|
@@ -2278,7 +2707,7 @@ function writeArtQuickCodePrologueArm64 (target, trampoline, redirectSize) {
|
|
|
2278
2707
|
|
|
2279
2708
|
const artQuickCodeHookRedirectSize = {
|
|
2280
2709
|
ia32: 5,
|
|
2281
|
-
x64:
|
|
2710
|
+
x64: 16,
|
|
2282
2711
|
arm: 8,
|
|
2283
2712
|
arm64: 16
|
|
2284
2713
|
};
|
|
@@ -2941,7 +3370,7 @@ const threadStateTransitionRecompilers = {
|
|
|
2941
3370
|
arm64: recompileExceptionClearForArm64
|
|
2942
3371
|
};
|
|
2943
3372
|
|
|
2944
|
-
function
|
|
3373
|
+
function makeArtThreadStateTransitionImpl (vm, env, callback) {
|
|
2945
3374
|
const envVtable = env.handle.readPointer();
|
|
2946
3375
|
const exceptionClearImpl = envVtable.add(ENV_VTABLE_OFFSET_EXCEPTION_CLEAR).readPointer();
|
|
2947
3376
|
const nextFuncImpl = envVtable.add(ENV_VTABLE_OFFSET_FATAL_ERROR).readPointer();
|
|
@@ -2952,7 +3381,6 @@ function _getArtThreadStateTransitionImpl (vm, env) {
|
|
|
2952
3381
|
}
|
|
2953
3382
|
|
|
2954
3383
|
let perform = null;
|
|
2955
|
-
const callback = new NativeCallback(onThreadStateTransitionComplete, 'void', ['pointer']);
|
|
2956
3384
|
|
|
2957
3385
|
const threadOffsets = getArtThreadSpec(vm).offset;
|
|
2958
3386
|
|
package/lib/class-factory.js
CHANGED
|
@@ -1680,6 +1680,8 @@ function handleMethodInvocation (jniArgs, params) {
|
|
|
1680
1680
|
env.pushLocalFrame(3);
|
|
1681
1681
|
let haveFrame = true;
|
|
1682
1682
|
|
|
1683
|
+
vm.link(tid, env);
|
|
1684
|
+
|
|
1683
1685
|
try {
|
|
1684
1686
|
pendingCalls.add(tid);
|
|
1685
1687
|
|
|
@@ -1727,6 +1729,8 @@ function handleMethodInvocation (jniArgs, params) {
|
|
|
1727
1729
|
|
|
1728
1730
|
return retType.defaultValue;
|
|
1729
1731
|
} finally {
|
|
1732
|
+
vm.unlink(tid);
|
|
1733
|
+
|
|
1730
1734
|
if (haveFrame) {
|
|
1731
1735
|
env.popLocalFrame(NULL);
|
|
1732
1736
|
}
|
package/lib/vm.js
CHANGED
|
@@ -6,15 +6,14 @@ const JNI_VERSION_1_6 = 0x00010006;
|
|
|
6
6
|
const pointerSize = Process.pointerSize;
|
|
7
7
|
|
|
8
8
|
const jsThreadID = Process.getCurrentThreadId();
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const attachedThreads = new Map();
|
|
10
|
+
const activeEnvs = new Map();
|
|
11
11
|
|
|
12
12
|
function VM (api) {
|
|
13
13
|
const handle = api.vm;
|
|
14
14
|
let attachCurrentThread = null;
|
|
15
15
|
let detachCurrentThread = null;
|
|
16
16
|
let getEnv = null;
|
|
17
|
-
const attachedThreads = new Map();
|
|
18
17
|
|
|
19
18
|
function initialize () {
|
|
20
19
|
const vtable = handle.readPointer();
|
|
@@ -31,25 +30,29 @@ function VM (api) {
|
|
|
31
30
|
this.perform = function (fn) {
|
|
32
31
|
const threadId = Process.getCurrentThreadId();
|
|
33
32
|
|
|
34
|
-
const
|
|
35
|
-
if (
|
|
36
|
-
return fn(
|
|
33
|
+
const cachedEnv = tryGetCachedEnv(threadId);
|
|
34
|
+
if (cachedEnv !== null) {
|
|
35
|
+
return fn(cachedEnv);
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
let env = this.
|
|
38
|
+
let env = this._tryGetEnv();
|
|
40
39
|
const alreadyAttached = env !== null;
|
|
41
40
|
if (!alreadyAttached) {
|
|
42
41
|
env = this.attachCurrentThread();
|
|
43
|
-
|
|
44
|
-
jsEnv = env;
|
|
45
|
-
} else {
|
|
46
|
-
attachedThreads.set(threadId, true);
|
|
47
|
-
}
|
|
42
|
+
attachedThreads.set(threadId, true);
|
|
48
43
|
}
|
|
49
44
|
|
|
45
|
+
this.link(threadId, env);
|
|
46
|
+
|
|
50
47
|
try {
|
|
51
48
|
return fn(env);
|
|
52
49
|
} finally {
|
|
50
|
+
const isJsThread = threadId === jsThreadID;
|
|
51
|
+
|
|
52
|
+
if (!isJsThread) {
|
|
53
|
+
this.unlink(threadId);
|
|
54
|
+
}
|
|
55
|
+
|
|
53
56
|
if (!alreadyAttached && !isJsThread) {
|
|
54
57
|
const allowedToDetach = attachedThreads.get(threadId);
|
|
55
58
|
attachedThreads.delete(threadId);
|
|
@@ -74,14 +77,17 @@ function VM (api) {
|
|
|
74
77
|
this.preventDetachDueToClassLoader = function () {
|
|
75
78
|
const threadId = Process.getCurrentThreadId();
|
|
76
79
|
|
|
77
|
-
if (threadId
|
|
78
|
-
jsThreadDetachAllowed = false;
|
|
79
|
-
} else if (attachedThreads.has(threadId)) {
|
|
80
|
+
if (attachedThreads.has(threadId)) {
|
|
80
81
|
attachedThreads.set(threadId, false);
|
|
81
82
|
}
|
|
82
83
|
};
|
|
83
84
|
|
|
84
85
|
this.getEnv = function () {
|
|
86
|
+
const cachedEnv = tryGetCachedEnv(Process.getCurrentThreadId());
|
|
87
|
+
if (cachedEnv !== null) {
|
|
88
|
+
return cachedEnv;
|
|
89
|
+
}
|
|
90
|
+
|
|
85
91
|
const envBuf = Memory.alloc(pointerSize);
|
|
86
92
|
const result = getEnv(handle, envBuf, JNI_VERSION_1_6);
|
|
87
93
|
if (result === -2) {
|
|
@@ -92,6 +98,15 @@ function VM (api) {
|
|
|
92
98
|
};
|
|
93
99
|
|
|
94
100
|
this.tryGetEnv = function () {
|
|
101
|
+
const cachedEnv = tryGetCachedEnv(Process.getCurrentThreadId());
|
|
102
|
+
if (cachedEnv !== null) {
|
|
103
|
+
return cachedEnv;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return this._tryGetEnv();
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
this._tryGetEnv = function () {
|
|
95
110
|
const envBuf = Memory.alloc(pointerSize);
|
|
96
111
|
const result = getEnv(handle, envBuf, JNI_VERSION_1_6);
|
|
97
112
|
if (result !== JNI_OK) {
|
|
@@ -108,12 +123,38 @@ function VM (api) {
|
|
|
108
123
|
};
|
|
109
124
|
};
|
|
110
125
|
|
|
126
|
+
this.link = function (tid, env) {
|
|
127
|
+
const entry = activeEnvs.get(tid);
|
|
128
|
+
if (entry === undefined) {
|
|
129
|
+
activeEnvs.set(tid, [env, 1]);
|
|
130
|
+
} else {
|
|
131
|
+
entry[1]++;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
this.unlink = function (tid) {
|
|
136
|
+
const entry = activeEnvs.get(tid);
|
|
137
|
+
if (entry[1] === 1) {
|
|
138
|
+
activeEnvs.delete(tid);
|
|
139
|
+
} else {
|
|
140
|
+
entry[1]--;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
function tryGetCachedEnv (threadId) {
|
|
145
|
+
const entry = activeEnvs.get(threadId);
|
|
146
|
+
if (entry === undefined) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
return entry[0];
|
|
150
|
+
}
|
|
151
|
+
|
|
111
152
|
initialize.call(this);
|
|
112
153
|
}
|
|
113
154
|
|
|
114
155
|
VM.dispose = function (vm) {
|
|
115
|
-
if (
|
|
116
|
-
|
|
156
|
+
if (attachedThreads.get(jsThreadID) === true) {
|
|
157
|
+
attachedThreads.delete(jsThreadID);
|
|
117
158
|
vm.detachCurrentThread();
|
|
118
159
|
}
|
|
119
160
|
};
|