provider.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. class Log {
  2. static TAG = '[system_server]'
  3. static Debug = true
  4. static format(...msg) {
  5. let m = []
  6. for (let i = 0; i < msg.length; i++) {
  7. if (typeof msg[i] === 'object') {
  8. m.push(msg[i] + '')
  9. } else {
  10. m.push(msg[i])
  11. }
  12. }
  13. m = m.join(' ')
  14. return m
  15. }
  16. static i(...msg) {
  17. if (!this.Debug) return
  18. console.log(`\x1b[30m${this.TAG} ${this.format(...msg)}\x1b[0m`)
  19. }
  20. static w(...msg) {
  21. console.log(`\x1b[33m${this.TAG} ${this.format(...msg)}\x1b[0m`)
  22. }
  23. static e(...msg) {
  24. console.log(`\x1b[31m${this.TAG} ${this.format(...msg)}\x1b[0m`)
  25. }
  26. static s(...msg) {
  27. console.log(`\x1b[32m${this.TAG} ${this.format(...msg)}\x1b[0m`)
  28. }
  29. }
  30. function trace(tag) {
  31. Log.e((tag || '') + Java.use('android.util.Log').getStackTraceString(Java.use('java.lang.Throwable').$new()))
  32. }
  33. function randomMac() {
  34. var mac = '00:16:3e'
  35. for (var i = 0; i < 3; i++) {
  36. mac += ':' + ('00' + Math.floor(Math.random() * 256).toString(16)).slice(-2)
  37. }
  38. return mac
  39. }
  40. function buff2json(buf) {
  41. console.log(`buffer length: ${buf.byteLength}`)
  42. try {
  43. var decoded = String.fromCharCode(...new Uint8Array(buf))
  44. console.log(`decoded: ${decoded}`)
  45. return JSON.parse(decoded.trim())
  46. } catch (e) {
  47. console.error(e)
  48. return null
  49. }
  50. }
  51. class Interaction {
  52. failure(err) {
  53. console.error(err.message)
  54. Java.use('android.util.Log').d('frida-system_server', err.message)
  55. }
  56. accepted(connection) {
  57. console.warn('accepted')
  58. connection.input.read(2000).then((data) => {
  59. Java.use('android.util.Log').d('frida-system_server', data + '')
  60. try {
  61. const json = buff2json(data)
  62. console.log('received', json)
  63. this.messageFn && this.messageFn(json)
  64. } catch (e) {}
  65. connection.close()
  66. })
  67. }
  68. accept_loop(listener) {
  69. var next_iter = this.accept_loop.bind(this, listener)
  70. listener
  71. .accept()
  72. .then(this.accepted.bind(this))
  73. .catch(this.failure.bind(this))
  74. .finally(function () {
  75. setImmediate(next_iter)
  76. })
  77. }
  78. listened(listener) {
  79. console.warn('listened')
  80. this.accept_loop(listener)
  81. }
  82. start(port, messageFn) {
  83. this.messageFn = messageFn
  84. console.warn('starting on port', port)
  85. Socket.listen({ family: 'ipv4', host: '0.0.0.0', port: port })
  86. .then(this.listened.bind(this))
  87. .catch(this.failure.bind(this))
  88. }
  89. }
  90. setImmediate(() => {
  91. Java.perform(function () {
  92. const Uri = Java.use('android.net.Uri')
  93. const File = Java.use('java.io.File')
  94. const BufferedReader = Java.use('java.io.BufferedReader')
  95. const FileInputStream = Java.use('java.io.FileInputStream')
  96. const FileOutputStream = Java.use('java.io.FileOutputStream')
  97. const InputStreamReader = Java.use('java.io.InputStreamReader')
  98. const OutputStreamWriter = Java.use('java.io.OutputStreamWriter')
  99. function getContext() {
  100. try {
  101. var ActivityThread = Java.use('android.app.ActivityThread')
  102. var application = ActivityThread.currentApplication()
  103. return application.getApplicationContext()
  104. } catch (e) {
  105. console.log(e)
  106. return null
  107. }
  108. }
  109. function readFile(file) {
  110. if (!file.exists()) {
  111. return null
  112. }
  113. var fileInputStream = FileInputStream.$new(file)
  114. var inputStreamReader = InputStreamReader.$new(Java.cast(fileInputStream, Java.use('java.io.InputStream')))
  115. var bufferedReader = BufferedReader.$new(inputStreamReader)
  116. var line
  117. var content = ''
  118. while ((line = bufferedReader.readLine()) !== null) {
  119. content += line + '\n'
  120. }
  121. bufferedReader.close()
  122. inputStreamReader.close()
  123. fileInputStream.close()
  124. return content
  125. }
  126. function writeFile(file, content) {
  127. if (!file.exists()) {
  128. file.createNewFile()
  129. }
  130. var fileOutputStream = FileOutputStream.$new(file)
  131. var outputStreamWriter = OutputStreamWriter.$new(
  132. Java.cast(fileOutputStream, Java.use('java.io.OutputStream'))
  133. )
  134. outputStreamWriter.write(content, 0, content.length)
  135. outputStreamWriter.flush()
  136. outputStreamWriter.close()
  137. fileOutputStream.close()
  138. }
  139. function readConfig() {
  140. const configFile = File.$new('/data/system/config.json')
  141. log(`read config from ${configFile.getAbsolutePath()}`)
  142. const json = readFile(configFile)
  143. if (!json) {
  144. return {}
  145. } else {
  146. log(`config: ${json}`)
  147. return JSON.parse(json)
  148. }
  149. }
  150. function saveConfig(config) {
  151. const configFile = File.$new('/data/system/config.json')
  152. log(`save config to ${configFile.getAbsolutePath()}`)
  153. const json = JSON.stringify(config)
  154. log(`config: ${json}`)
  155. writeFile(configFile, json)
  156. }
  157. function queryConfig(key) {
  158. const context = getContext()
  159. if (!context) {
  160. return null
  161. }
  162. const cr = context.getContentResolver()
  163. const uri = Uri.parse('content://SimInfo')
  164. const cursor = cr.query(uri, null, null, null, null)
  165. if (!cursor) {
  166. return null
  167. }
  168. if (!cursor.moveToFirst()) {
  169. cursor.close()
  170. return null
  171. }
  172. const idx = cursor.getColumnIndex(key)
  173. if (idx < 0) {
  174. cursor.close()
  175. return null
  176. }
  177. const value = cursor.getString(idx)
  178. cursor.close()
  179. return value
  180. }
  181. const ActivityThread = Java.use('android.app.ActivityThread')
  182. ActivityThread.installContentProviders.overload('android.content.Context', 'java.util.List').implementation =
  183. function (context, providers) {
  184. Log.i('installContentProviders')
  185. const res = this.installContentProviders(context, providers)
  186. return res
  187. }
  188. const ContentProviderHelper = Java.use('com.android.server.am.ContentProviderHelper')
  189. ContentProviderHelper.getContentProvider.overload(
  190. 'android.app.IApplicationThread',
  191. 'java.lang.String',
  192. 'java.lang.String',
  193. 'int',
  194. 'boolean'
  195. ).implementation = function (caller, name, callingPkg, callingUid, stable) {
  196. Log.i(`getContentProvider(${name}, ${callingPkg})`)
  197. const res = this.getContentProvider(caller, name, callingPkg, callingUid, stable)
  198. return res
  199. }
  200. ContentProviderHelper.getContentProviderExternal.overload(
  201. 'java.lang.String',
  202. 'int',
  203. 'android.os.IBinder',
  204. 'java.lang.String'
  205. ).implementation = function (name, userId, token, tag) {
  206. Log.i(`getContentProviderExternal(${name})`)
  207. const res = this.getContentProviderExternal(name, userId, token, tag)
  208. return res
  209. }
  210. const classLoaders = Java.enumerateClassLoadersSync()
  211. classLoaders.find((i) => Log.i(i.toString()))
  212. // Log.i('SettingsProviderClassLoader: ' + SettingsProviderClassLoader)
  213. // Java.classFactory.loader = SettingsProviderClassLoader
  214. // const genRanHex = (size) => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join('')
  215. // const ssaidGms = genRanHex(16)
  216. // const ssaidVending = genRanHex(16)
  217. // const SettingsProvider = Java.use('com.android.providers.settings.SettingsProvider')
  218. // SettingsProvider.getSecureSetting.overload('java.lang.String', 'int').implementation = function (key, userId) {
  219. // const res = this.getSecureSetting(key, userId)
  220. // Log.i(`getSecureSetting(${key}, ${userId}) = ${res}`)
  221. // if (key === 'android_id') {
  222. // Log.e(`getSystemSetting(${key}, ${userId}) = ${ssaidGms}`)
  223. // if (res.getPackageName() === 'com.google.android.gms') {
  224. // Log.s(`spoofed ${res.value} -> ${ssaidGms}`)
  225. // res.value.value = ssaidGms
  226. // } else if (res.getPackageName() === 'com.android.vending') {
  227. // Log.s(`spoofed ${res.value} -> ${ssaidGms}`)
  228. // res.value.value = ssaidVending
  229. // }
  230. // }
  231. // return res
  232. // }
  233. // SettingsProvider.getGlobalSetting.overload('java.lang.String').implementation = function (key) {
  234. // const res = this.getGlobalSetting(key)
  235. // Log.i(`getGlobalSetting(${key}) = ${res}`)
  236. // return res
  237. // }
  238. // SettingsProvider.getSystemSetting.overload('java.lang.String', 'int').implementation = function (key, userId) {
  239. // const res = this.getSystemSetting(key, userId)
  240. // Log.i(`getSystemSetting(${key}, ${userId}) = ${res}`)
  241. // return res
  242. // }
  243. // SettingsProvider.query.overload(
  244. // 'android.net.Uri',
  245. // '[Ljava.lang.String;',
  246. // 'java.lang.String',
  247. // '[Ljava.lang.String;',
  248. // 'java.lang.String'
  249. // ).implementation = function (uri, projection, selection, selectionArgs, sortOrder) {
  250. // Log.i(`query(${uri}, ${projection}, ${selection}, ${selectionArgs}, ${sortOrder})`)
  251. // return this.query(uri, projection, selection, selectionArgs, sortOrder)
  252. // }
  253. })
  254. })