provider.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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 classLoaders = Java.enumerateClassLoadersSync()
  182. const SettingsProviderClassLoader = classLoaders.find((i) => i.toString().includes('SettingsProvider'))
  183. Log.i('SettingsProviderClassLoader: ' + SettingsProviderClassLoader)
  184. Java.classFactory.loader = SettingsProviderClassLoader
  185. const genRanHex = (size) => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join('')
  186. const ssaidGms = genRanHex(16)
  187. const ssaidVending = genRanHex(16)
  188. const SettingsProvider = Java.use('com.android.providers.settings.SettingsProvider')
  189. SettingsProvider.getSecureSetting.overload('java.lang.String', 'int').implementation = function (key, userId) {
  190. const res = this.getSecureSetting(key, userId)
  191. Log.i(`getSecureSetting(${key}, ${userId}) = ${res}`)
  192. if (key === 'android_id') {
  193. Log.e(`getSystemSetting(${key}, ${userId}) = ${ssaidGms}`)
  194. if (res.getPackageName() === 'com.google.android.gms') {
  195. Log.s(`spoofed ${res.value} -> ${ssaidGms}`)
  196. res.value.value = ssaidGms
  197. } else if (res.getPackageName() === 'com.android.vending') {
  198. Log.s(`spoofed ${res.value} -> ${ssaidGms}`)
  199. res.value.value = ssaidVending
  200. }
  201. }
  202. return res
  203. }
  204. SettingsProvider.getGlobalSetting.overload('java.lang.String').implementation = function (key) {
  205. const res = this.getGlobalSetting(key)
  206. Log.i(`getGlobalSetting(${key}) = ${res}`)
  207. return res
  208. }
  209. SettingsProvider.getSystemSetting.overload('java.lang.String', 'int').implementation = function (key, userId) {
  210. const res = this.getSystemSetting(key, userId)
  211. Log.i(`getSystemSetting(${key}, ${userId}) = ${res}`)
  212. return res
  213. }
  214. SettingsProvider.query.overload(
  215. 'android.net.Uri',
  216. '[Ljava.lang.String;',
  217. 'java.lang.String',
  218. '[Ljava.lang.String;',
  219. 'java.lang.String'
  220. ).implementation = function (uri, projection, selection, selectionArgs, sortOrder) {
  221. Log.i(`query(${uri}, ${projection}, ${selection}, ${selectionArgs}, ${sortOrder})`)
  222. return this.query(uri, projection, selection, selectionArgs, sortOrder)
  223. }
  224. })
  225. })