dumper.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. import {DUMP_FILE_PATH, soName} from "./dumpconfig";
  2. import {il2cppApi} from "./il2cpp/il2cppApi";
  3. import {log} from "./logger";
  4. let classAllCount = 0;
  5. let file = new File(DUMP_FILE_PATH, "wb");
  6. let il2cpp_got = false;
  7. let once =false;
  8. export var dumper = {
  9. waitInject: function () {
  10. log("waitInject");
  11. let open = Module.findExportByName(null, "open");
  12. //fopen替换
  13. log("等待Il2cpp:" + open);
  14. if (open != null) {
  15. Interceptor.attach(open, {
  16. onEnter: function (args) {
  17. let path = args[0].readCString();
  18. // log("path:" + path);
  19. if (path.indexOf(soName) !== -1) {
  20. this.hook = true;
  21. }
  22. },
  23. onLeave: function (retval) {
  24. // log("this.hook:" + this.hook);
  25. if (this.hook) {
  26. il2cpp_got = true;
  27. // Interceptor.detachAll();
  28. dumper.start();
  29. }
  30. }
  31. })
  32. }
  33. },
  34. start: function () {
  35. let module = Process.findModuleByName(soName);
  36. log("module:"+module);
  37. if (module == null) {
  38. if (il2cpp_got) {
  39. setTimeout(function () {
  40. //执行
  41. dumper.start();
  42. }, 5000);
  43. return;
  44. }
  45. this.waitInject();
  46. return
  47. }
  48. //延迟一下
  49. log("module "+module.path +" addr "+module.base);
  50. setTimeout(function (){
  51. if (once){
  52. return
  53. }
  54. once=true;
  55. module = Process.findModuleByName(soName);
  56. let baseAddress = module.base;
  57. log("base address:" + baseAddress);
  58. let domain = il2cppApi.il2cpp_domain_get();
  59. let size_t = Memory.alloc(Process.pointerSize);
  60. log("domain:" + domain + " baseAddress:" + baseAddress);
  61. //可能还没加载
  62. let assemblies = il2cppApi.il2cpp_domain_get_assemblies(domain, size_t);
  63. let assemblies_count = size_t.readInt();
  64. log("assemblies_count:" + assemblies_count + " pointerSize:" + Process.pointerSize
  65. + " assemblies:" + assemblies);
  66. if (assemblies_count===0){
  67. setTimeout(function (){
  68. this.start();
  69. },2000);
  70. return;
  71. }
  72. let il2CppImageArray = new Array();
  73. for (let i = 0; i < assemblies_count; i++) {
  74. let assembly = assemblies.add(Process.pointerSize * i).readPointer();
  75. let Il2CppImage = il2cppApi.il2cpp_assembly_get_image(assembly);
  76. let typeStart = Il2CppImage.typeStart();
  77. log("typeStart:" + typeStart + " name:" + Il2CppImage.nameNoExt()+" typeCount:"+Il2CppImage.typeCount());
  78. dumper.out(" // Image :" + i + " " + Il2CppImage.nameNoExt() + " - " + Il2CppImage.typeStart() + "\n")
  79. il2CppImageArray.push(Il2CppImage);
  80. }
  81. for (let i = 0; i < il2CppImageArray.length; i++) {
  82. log("process: " + (i + 1) + "/" + assemblies_count);
  83. let Il2CppImage = il2CppImageArray[i];
  84. let nameNoExt = Il2CppImage.nameNoExt();
  85. let start = Il2CppImage.typeStart();
  86. let class_count = Il2CppImage.typeCount();
  87. // log("name:"+nameNoExt +" start:"+start +" count:"+class_count)
  88. // if (nameNoExt === "Assembly-CSharp") {
  89. // // dll
  90. // this.out("\n//assembly Image -->:" + nameNoExt + " startIndex:" + start + " typeCount:" + class_count);
  91. dumper.findAllClass(Il2CppImage);
  92. // }
  93. }
  94. log("dump end")
  95. log("classAllCount:" + classAllCount);
  96. // log("nativeFunNotExistMap:" + il2cppApi.nativeFunNotExistMap.size);
  97. if (il2cppApi.nativeFunNotExistMap.size > 0) {
  98. log("some NativeFun is un exist ,parser will be not accurate :");
  99. il2cppApi.nativeFunNotExistMap.forEach(function (value, key) {
  100. log(key + "");
  101. })
  102. }
  103. log("module "+module.path +" addr "+module.base);
  104. },20000);
  105. },
  106. findAllClass: function (il2cppImage) {
  107. let class_count = il2cppImage.typeCount();
  108. classAllCount = classAllCount + class_count;
  109. log("findAllClass "+il2cppImage.name()+" class_count:" + class_count)
  110. for (let i = 0; i < class_count; i++) {
  111. log("class process:"+i +"/"+class_count)
  112. let il2CppClass = il2cppImage.getClass(i);
  113. let il2CppType = il2CppClass.getType();
  114. let declaringType = il2CppClass.getDeclaringType();
  115. if (!declaringType.isNull()) {
  116. // log("declaringType:" + declaringType.name() + " class:" + il2CppClass.name());
  117. }
  118. this.dumpType(il2CppType);
  119. }
  120. },
  121. dumpType: function (il2CppType) {
  122. let klass = il2cppApi.il2cpp_class_from_type(il2CppType);
  123. let il2CppImage = il2cppApi.il2cpp_class_get_image(klass);
  124. this.out("\n//Namespace:" + klass.namespaze() + " Image->" + il2CppImage.name() + "\n")
  125. let flags = klass.flags();
  126. let Serializable = flags & tabledefs.TYPE_ATTRIBUTE_SERIALIZABLE;
  127. if (Serializable) {
  128. this.out('[Serializable]\n')
  129. }
  130. let visibility = flags & tabledefs.TYPE_ATTRIBUTE_VISIBILITY_MASK;
  131. switch (visibility) {
  132. case tabledefs.TYPE_ATTRIBUTE_PUBLIC:
  133. case tabledefs.TYPE_ATTRIBUTE_NESTED_PUBLIC:
  134. this.out("public ")
  135. break;
  136. case tabledefs.TYPE_ATTRIBUTE_NOT_PUBLIC:
  137. case tabledefs.TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
  138. case tabledefs.TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
  139. this.out("internal ")
  140. break;
  141. case tabledefs.TYPE_ATTRIBUTE_NESTED_PRIVATE:
  142. this.out("private ")
  143. break;
  144. case tabledefs.TYPE_ATTRIBUTE_NESTED_FAMILY:
  145. this.out("protected ")
  146. break;
  147. case tabledefs.TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
  148. this.out("protected internal ")
  149. break;
  150. }
  151. let isValuetype = klass.valueType();
  152. let IsEnum = klass.enumType();
  153. if (flags & tabledefs.TYPE_ATTRIBUTE_ABSTRACT && flags & tabledefs.TYPE_ATTRIBUTE_SEALED) {
  154. this.out("static ")
  155. } else if (!(flags & tabledefs.TYPE_ATTRIBUTE_INTERFACE) && flags & tabledefs.TYPE_ATTRIBUTE_ABSTRACT) {
  156. this.out("abstract ")
  157. } else if (!isValuetype && !IsEnum && flags & tabledefs.TYPE_ATTRIBUTE_SEALED) {
  158. this.out("sealed ")
  159. }
  160. if (flags & tabledefs.TYPE_ATTRIBUTE_INTERFACE) {
  161. this.out("interface ")
  162. } else if (IsEnum) {
  163. this.out("enum ")
  164. } else if (isValuetype) {
  165. this.out("struct ");
  166. } else {
  167. this.out("class ");
  168. }
  169. let name = klass.name();
  170. //获取泛型
  171. if (name.indexOf("`") !== -1) {
  172. let split = name.split("`");
  173. name = split[0];
  174. name = name + klass.getGenericName();
  175. }
  176. this.out(name + " ");
  177. let klass_parent = klass.parent();
  178. //父类
  179. let hasParent = false;
  180. if (!isValuetype && !IsEnum && !klass_parent.isNull()) {
  181. let parent_cls_type = klass_parent.getType();
  182. let typeEnum = parent_cls_type.getTypeEnum();
  183. if (typeEnum === Il2CppTypeEnum.IL2CPP_TYPE_OBJECT) {
  184. //not out
  185. } else {
  186. hasParent = true;
  187. this.out(": " + klass_parent.name());
  188. }
  189. }
  190. //实现接口类
  191. let iter = Memory.alloc(Process.pointerSize);
  192. let interfaces;
  193. while (!(interfaces = klass.getInterfaces(iter)).isNull()) {
  194. let interfaces_name = interfaces.name();
  195. if (interfaces_name.indexOf("`") !== -1) {
  196. let split = interfaces_name.split("`");
  197. interfaces_name = split[0];
  198. interfaces_name = interfaces_name + interfaces.getGenericName();
  199. }
  200. if (!hasParent) {
  201. this.out(": " + interfaces_name)
  202. hasParent = true;
  203. } else {
  204. this.out(", " + interfaces_name);
  205. }
  206. }
  207. this.out("\n{\n")
  208. this.dumpFiled(klass);
  209. this.dumpPropertyInfo(klass);
  210. this.dumpMethod(klass);
  211. this.out("\n}");
  212. },
  213. dumpMethod: function (klass) {
  214. let iter = Memory.alloc(Process.pointerSize);
  215. let methodInfo;
  216. let isFirst = true;
  217. let baseAddr = Module.findBaseAddress(soName);
  218. while (!(methodInfo = klass.getMethods(iter)).isNull()) {
  219. if (isFirst) {
  220. this.out("\n\t//methods\n");
  221. isFirst = false;
  222. }
  223. let methodPointer = methodInfo.getMethodPointer();
  224. let generic = methodInfo.is_generic();
  225. let inflated = methodInfo.is_inflated();
  226. // log("generic:"+generic +" inflated:"+inflated +"name:"+methodInfo.name());
  227. if (!methodPointer.isNull()) {
  228. let number = methodPointer - baseAddr;
  229. if (number===0x4CC8B94){
  230. let nativePointer = klass.add(16).readPointer();
  231. logHHex(nativePointer);
  232. log("class :"+klass.name()+ "length:"+klass.name().length);
  233. }
  234. this.out("\t// RVA: 0x" + number.toString(16).toUpperCase());
  235. this.out(" VA: 0x");
  236. this.out(methodPointer.toString(16).toUpperCase());
  237. } else {
  238. this.out("\t// RVA: 0x VA: 0x0");
  239. }
  240. //非必须
  241. // log("slot:" + methodInfo.getSlot());
  242. // if (methodInfo.getSlot() !== 65535) {
  243. // this.out(" Slot: " + methodInfo.getSlot());
  244. // }
  245. this.out("\n\t");
  246. let methodModifier = utils.get_method_modifier(methodInfo.getFlags());
  247. this.out(methodModifier);
  248. let returnType = methodInfo.getReturnType();
  249. let return_cls = il2cppApi.il2cpp_class_from_type(returnType);
  250. this.out(return_cls.name() + " " + methodInfo.name() + "(");
  251. let paramCount = methodInfo.getParamCount();
  252. // log("paramCount:" + paramCount);
  253. if (paramCount > 0) {
  254. for (let i = 0; i < paramCount; i++) {
  255. let paramType = methodInfo.getParam(i);
  256. let paramCls = il2cppApi.il2cpp_class_from_type(paramType);
  257. let name = paramCls.name();
  258. //获取泛型
  259. if (name.indexOf("`") !== -1) {
  260. let split = name.split("`");
  261. name = split[0];
  262. name = name + paramCls.getGenericName();
  263. }
  264. this.out(name + " " + methodInfo.getParamName(i));
  265. if (i + 1 !== paramCount) {
  266. this.out(", ");
  267. } else {
  268. this.out(") { }\n");
  269. }
  270. }
  271. } else {
  272. this.out("){ }\n");
  273. }
  274. }
  275. },
  276. dumpPropertyInfo: function (klass) {
  277. let iter = Memory.alloc(Process.pointerSize);
  278. let propertyInfo;
  279. let isFirst = true;
  280. while (!(propertyInfo = klass.getProperties(iter)).isNull()) {
  281. if (isFirst) {
  282. this.out("\n\t// Properties\n");
  283. isFirst = false;
  284. }
  285. this.out("\t");
  286. //获取getSet
  287. // log(" dumpPropertyInfo get:" + propertyInfo.getMethod().isNull());
  288. let pro_class;
  289. let method = propertyInfo.getMethod();
  290. let setMethod = propertyInfo.setMethod();
  291. if (method.isNull() && setMethod.isNull()) {
  292. continue;
  293. }
  294. if (!method.isNull()) {
  295. let methodModifier = utils.get_method_modifier(method.getFlags());
  296. // let methodPointer = method.getMethodPointer()
  297. // log("methodModifier:" + methodModifier + " methodPointer:" + methodPointer);
  298. this.out(methodModifier);
  299. pro_class = il2cppApi.il2cpp_class_from_type(method.getReturnType());
  300. } else if (!setMethod.isNull()) {
  301. let setModifier = utils.get_method_modifier(setMethod.getFlags());
  302. this.out(setModifier);
  303. pro_class = il2cppApi.il2cpp_class_from_type(setMethod.getReturnType());
  304. }
  305. // log("pro_class:"+pro_class +"propertyInfo:"+propertyInfo.getName() +" method:"+method +" setMethod:"+setMethod)
  306. this.out(pro_class.name() + " " + propertyInfo.getName() + " { ");
  307. if (!method.isNull()) {
  308. this.out("get; ");
  309. }
  310. if (!setMethod.isNull()) {
  311. this.out("set; ");
  312. }
  313. this.out("}\n");
  314. }
  315. },
  316. dumpFiled: function (klass) {
  317. // log("dumpFiled class :" + klass.name())
  318. let filedCount = klass.filedCount();
  319. // log("fieldCount:" + filedCount);
  320. if (filedCount > 0) {
  321. let iter = Memory.alloc(Process.pointerSize);
  322. let filedInfo;
  323. this.out("\t//Fileds\n");
  324. while (!(filedInfo = klass.getFieldsInfo(iter)).isNull()) {
  325. let flags = filedInfo.getFlags();
  326. this.out("\t")
  327. let access = flags & tabledefs.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
  328. switch (access) {
  329. case tabledefs.FIELD_ATTRIBUTE_PRIVATE:
  330. this.out("private ")
  331. break;
  332. case tabledefs.FIELD_ATTRIBUTE_PUBLIC:
  333. this.out("public ")
  334. break;
  335. case tabledefs.FIELD_ATTRIBUTE_FAMILY:
  336. this.out("protected ")
  337. break;
  338. case tabledefs.FIELD_ATTRIBUTE_ASSEMBLY:
  339. case tabledefs.FIELD_ATTRIBUTE_FAM_AND_ASSEM:
  340. this.out("internal ")
  341. break;
  342. case tabledefs.FIELD_ATTRIBUTE_FAM_OR_ASSEM:
  343. this.out("protected internal ")
  344. break;
  345. }
  346. if (flags & tabledefs.FIELD_ATTRIBUTE_LITERAL) {
  347. this.out("const ")
  348. } else {
  349. if (flags & tabledefs.FIELD_ATTRIBUTE_STATIC) {
  350. this.out("static ")
  351. }
  352. if (flags & tabledefs.FIELD_ATTRIBUTE_INIT_ONLY) {
  353. this.out("readonly ")
  354. }
  355. }
  356. let fieldClass = filedInfo.getFiledClass();
  357. let name = fieldClass.name(); //参数名
  358. let offset = filedInfo.getOffset();//偏移
  359. // //如果是泛型变量则进行补充
  360. if (name.indexOf("`") !== -1) { //`1 `2 `3 说明是泛型类型 解析泛型变量
  361. let genericName = fieldClass.getGenericName();
  362. let split = name.split("`");
  363. name = split[0];
  364. name = name + genericName;
  365. }
  366. this.out(name + " " + filedInfo.getFiledName());
  367. //获取常量的初始值
  368. // let filed_info_cpp_type = filedInfo.getType(); //获取变量参数类型
  369. // log("filed_info_cpp_type:" + filed_info_cpp_type.getTypeEnum() + name + " " + filedInfo.getFiledName());
  370. if (flags & tabledefs.FIELD_ATTRIBUTE_LITERAL) {
  371. // let staticValue = filedInfo.getStaticValue();
  372. // if (staticValue !== null) {
  373. // this.out(" = " + staticValue + ";\n");
  374. // }
  375. this.out(";\n");
  376. } else {
  377. this.out(" ;// 0x" + offset.toString(16).toUpperCase() + "\n");
  378. }
  379. }
  380. }
  381. },
  382. out: function (string) {
  383. file.write(string);
  384. file.flush();
  385. }
  386. }