java可以将任意对象序列化为一段内存流,也可以反序列化回对象。
此代码用于dump序列化内容流,是用了Jsoncpp作为父类。
主要参考了https://github.com/NickstaDB/SerializationDumper这个项目。
#pragma once #include <string> #include <vector> #include <cassert> #include "FStream.h" #include "json/json.h" // #ifdef _DEBUG // #pragma comment(lib, "jsoncpp/lib_json_mtd.lib") // #else // #pragma comment(lib, "jsoncpp/lib_json_mt.lib") // #endif // _DEBUG /* Java序列化内容(以0xACED开头)解析工具,转为jsoncpp的Json::Value 参考链接: https://github.com/NickstaDB/SerializationDumper 用法: JavaSerializationHandler jsonSerialize; jsonSerialize.OpenSerializationBuffer(buf); jsonSerialize.OpenSerializationFile(filepath); dumpjson(jsonSerialize); //直接就是Json::Value的子类,可以直接按照json使用 说明: 如果对象是Object,那么会该Object的json节点会出现几个元素(使用前还是要校验一下存在与否): "_desc" : 类的描述信息,包括类名、字段描述、父类信息等等 "_data" : 类的数据 "_block": 类的附加块数据,一些内置的java类型例如hashmap或者list等等会使用该字段,这里的数据一般需要二次整理,不要直接使用 "_array": 如果是Array类型数据例如java.util.ArrayList等,会出现该字段,类型是数组,数组的元素由_block字段中整理并保存到该字段下 "_hashmap":如果是java.util.HashMap类型数据会出现该字段,由_block字段中的数据整理并保存到该字段下 "_enum" : 暂时还没碰到过这个类型的数据样本,围观。。。 实例: 末尾部分。 */ class JavaSerializationHandler : public Json::Value { /******************* * Read a content element from the data stream. * * Could be any of: * TC_OBJECT (0x73) * TC_CLASS (0x76) * TC_ARRAY (0x75) * TC_STRING (0x74) * TC_LONGSTRING (0x7c) * TC_ENUM (0x7e) * TC_CLASSDESC (0x72) * TC_PROXYCLASSDESC (0x7d) * TC_REFERENCE (0x71) * TC_NULL (0x70) * TC_EXCEPTION (0x7b) * TC_RESET (0x79) * TC_BLOCKDATA (0x77) * TC_BLOCKDATALONG (0x7a) ******************/ enum classElementType { TC_NULL = 0x70, TC_REFERENCE = 0x71, TC_CLASSDESC = 0x72, TC_OBJECT = 0x73, TC_STRING = 0x74, TC_ARRAY = 0x75, TC_CLASS = 0x76, TC_BLOCKDATA = 0x77, TC_ENDBLOCKDATA = 0x78, TC_RESET = 0x79, TC_BLOCKDATALONG = 0x7a, TC_EXCEPTION = 0x7b, TC_LONGSTRING = 0x7c, TC_ENUM = 0x7e, TC_PROXYCLASSDESC = 0x7d }; enum classDescFlags { SC_WRITE_METHOD = 0x01, SC_SERIALIZABLE = 0x02, SC_EXTERNALIZABLE = 0x04, SC_BLOCK_DATA = 0x08 }; struct OBJECT_REF_DATA { uint32_t ref; uint8_t type; Json::Value data; }; #ifndef _bswap_16 /* Swap bytes in 16 bit value. */ #define _bswap_16(x) \ ((unsigned short int) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))) #endif #ifndef _bswap_32 /* Swap bytes in 32 bit value. */ #define _bswap_32(x) \ ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) #endif #ifndef _bswap_64 /* Swap bytes in 64 bit value. */ # define _bswap_64(x) \ ((((x) & 0xff00000000000000ull) >> 56) \ | (((x) & 0x00ff000000000000ull) >> 40) \ | (((x) & 0x0000ff0000000000ull) >> 24) \ | (((x) & 0x000000ff00000000ull) >> 8) \ | (((x) & 0x00000000ff000000ull) << 8) \ | (((x) & 0x0000000000ff0000ull) << 24) \ | (((x) & 0x000000000000ff00ull) << 40) \ | (((x) & 0x00000000000000ffull) << 56)) #endif public: JavaSerializationHandler() : m_refIndex(0x7e0000) {}; ~JavaSerializationHandler() {}; template<typename _T> bool OpenSerializationFile(const _T& filepath) { FFileStream infile(filepath); m_bufstream = &infile; bool ret = false; #ifdef _DEBUG ret = JavaSerializationParser(*this); #else try { ret = JavaSerializationParser(*this); } catch (...) {} #endif // _DEBUG return ret; } bool OpenSerializationBuffer(const std::string &buf) { FBufferStream stream(buf); m_bufstream = &stream; bool ret = false; #ifdef _DEBUG ret = JavaSerializationParser(*this); #else try { ret = JavaSerializationParser(*this); } catch (...) {} #endif // _DEBUG return ret; } private: FStream* m_bufstream; std::vector<OBJECT_REF_DATA> m_objectRefs; uint32_t m_refIndex; const char* getTypeString(uint8_t type) { //获取enum类型的字符串 switch (type) { case TC_NULL: return "TC_NULL"; case TC_REFERENCE: return "TC_REFERENCE"; case TC_CLASSDESC: return "TC_CLASSDESC"; case TC_OBJECT: return "TC_OBJECT"; case TC_STRING: return "TC_STRING"; case TC_ARRAY: return "TC_ARRAY"; case TC_CLASS: return "TC_CLASS"; case TC_BLOCKDATA: return "TC_BLOCKDATA"; case TC_ENDBLOCKDATA: return "TC_ENDBLOCKDATA"; case TC_RESET: return "TC_RESET"; case TC_BLOCKDATALONG: return "TC_BLOCKDATALONG"; case TC_EXCEPTION: return "TC_EXCEPTION"; case TC_LONGSTRING: return "TC_LONGSTRING"; case TC_ENUM: return "TC_ENUM"; } return "UNKNOWN"; } Json::Value getObjectByRef(uint32_t ref) { for (auto& obj : m_objectRefs) { if (obj.ref == ref) { #ifdef _DEBUG // if (obj.type == TC_STRING || obj.type == TC_LONGSTRING) // printf("get ref:0x%x, string:%s \n", ref, obj.data.asCString()); // else // printf("get ref:0x%x, type:%s(%x) \n", ref, getTypeString(obj.type), obj.type); #endif // _DEBUG return obj.data; break; } } return {}; } uint32_t setObjectRef(uint8_t type, const Json::Value& val) { m_objectRefs.emplace_back(OBJECT_REF_DATA{ m_refIndex , type, val }); #ifdef _DEBUG // if (type == TC_STRING || type == TC_LONGSTRING) // printf("new ref:0x%x, string:%s \n", m_refIndex, val.asCString()); // else // printf("new ref:0x%x, type:%s(%x) \n", m_refIndex, getTypeString(type), type); #endif // _DEBUG return m_refIndex++; } void updateObjectRef(uint32_t ref, uint8_t type, const Json::Value& val) { for (auto& obj : m_objectRefs) { if (obj.ref == ref) { obj.type = type; obj.data = val; break; } } } std::string tohex(const std::string& data) { std::string strRet; if (data.empty()) return strRet; strRet.reserve(data.length() * 2); const char* hex = "0123456789abcdef"; for (char ch : data) { strRet.push_back(hex[(unsigned char)ch >> 4]); strRet.push_back(hex[(unsigned char)ch & 0xf]); } return strRet; } bool readReference(uint32_t& ref) { if (!m_bufstream->read_data(ref)) return false; ref = _bswap_32(ref); return true; } bool readUtf(std::string& ret) { uint16_t len; if (!m_bufstream->read_data(len)) return false; len = _bswap_16(len); if (len && !m_bufstream->read_buffer(ret, len)) return false; return true; } bool readLongUtf(std::string& ret) { uint64_t len; if (!m_bufstream->read_data(len)) return false; len = _bswap_64(len); if (!m_bufstream->read_buffer(ret, (size_t)len)) return false; return true; } bool readNewString(Json::Value& val) { uint8_t type; if (!m_bufstream->read_data(type)) return false; if (type == TC_STRING || type == TC_LONGSTRING || type == TC_REFERENCE) return readContentElement(type, val); //剩下的类型都不对 return false; } bool readNewArray(Json::Value& jsonarray) { Json::Value jsonDesc; //Read the class data description to enable array elements to be read if (!readClassDesc(jsonDesc)) return false; if (!jsonDesc.isObject() || !jsonDesc["classname"].isString()) return false; std::string str = jsonDesc["classname"].asString(); if (str.length() < 2 || str[0] != '[') return false; uint8_t type = str[1]; jsonarray["_desc"] = jsonDesc; //索引值+1 int refindex = setObjectRef(TC_ARRAY, jsonarray); //array size uint32_t arraysize; if (!m_bufstream->read_data(arraysize)) return false; for (uint32_t i = 0; i < arraysize; i++) { if (!readFieldValue(type, jsonarray["_array"][i])) return false; } //更新值 updateObjectRef(refindex, TC_ARRAY, jsonarray); return true; } bool readFieldValue(int type, Json::Value& jsonvalue) { switch (type) { case 'B': //byte 1 uint8_t val; if (!m_bufstream->read_data(val)) return false; jsonvalue = val; break; case 'C': //char java里面的char占用2字节 case 'S': //short { uint16_t val; if (!m_bufstream->read_data(val)) return false; jsonvalue = _bswap_16(val); break; } case 'D': //double { uint64_t val; if (!m_bufstream->read_data(val)) return false; val = _bswap_64(val); jsonvalue = *(double*)&val; break; } case 'F': //float { uint32_t val; if (!m_bufstream->read_data(val)) return false; val = _bswap_32(val); jsonvalue = *(float*)&val; break; } case 'I': //int { uint32_t val; if (!m_bufstream->read_data(val)) return false; jsonvalue = (int32_t)_bswap_32(val); break; } case 'J': //long { uint64_t val; if (!m_bufstream->read_data(val)) return false; jsonvalue = (int64_t)_bswap_64(val); break; } case 'Z': //boolean { uint8_t val; if (!m_bufstream->read_data(val)) return false; if (val) jsonvalue = true; else jsonvalue = false; break; } case '[': //array case 'L': //object if (!readContentElement(jsonvalue)) return false; break; default: //Unknown field type printf("unknown filed type: %c\n", type); return false; } return true; } bool readClassAnnotation(Json::Value& jsonret) { //classAnnotation int index = 0; while (true) { uint8_t type; if (!m_bufstream->read_data(type)) return false; if (type == TC_ENDBLOCKDATA) break; if (!readContentElement(type, jsonret[index])) return false; index++; } return true; } bool readNewClassDesc(Json::Value& jsonret) { //由于desc很长很长,先占个坑把ref的index占了 uint32_t refindex = setObjectRef(TC_CLASSDESC, jsonret); //className std::string className; if (!readUtf(className)) return false; if (className.empty()) { printf("Error: class name is empty.\n"); return false; } jsonret["classname"] = className; //serialVersionUID 固定8字节 std::string serialVersionUID; if (!m_bufstream->read_buffer(serialVersionUID, 8)) return false; jsonret["uid"] = tohex(serialVersionUID); //classDescFlags uint8_t classflags; if (!m_bufstream->read_data(classflags)) return false; ////Validate classDescFlags if ((classflags & 0x02) == 0x02) { if ((classflags & 0x04) == 0x04) { printf("Error: Illegal classDescFlags, SC_SERIALIZABLE is not compatible with SC_EXTERNALIZABLE. \n"); return false; } if ((classflags & 0x08) == 0x08) { printf("Error: Illegal classDescFlags, SC_SERIALIZABLE is not compatible with SC_BLOCK_DATA. \n"); return false; } } else if ((classflags & 0x04) == 0x04) { if ((classflags & 0x01) == 0x01) { printf("Error: Illegal classDescFlags, SC_EXTERNALIZABLE is not compatible with SC_WRITE_METHOD.\n"); return false; } } else if (classflags != 0x00) { printf("Error: Illegal classDescFlags, must include either SC_SERIALIZABLE or SC_EXTERNALIZABLE. \n"); return false; } jsonret["flags"] = classflags; //read fields uint16_t fieldcount; if (!m_bufstream->read_data(fieldcount)) return false; fieldcount = _bswap_16(fieldcount); jsonret["fields"].resize(0); for (uint16_t i = 0; i < fieldcount; i++) { uint8_t fieldtype; if (!m_bufstream->read_data(fieldtype)) return false; jsonret["fields"][i]["type"] = fieldtype; std::string fieldname; if (!readUtf(fieldname)) return false; if (fieldname.empty()) { printf("Error: field name is empty.\n"); //return false; } jsonret["fields"][i]["name"] = fieldname; if (fieldtype == '[' || fieldtype == 'L') { if (!readNewString(jsonret["fields"][i]["classname"])) return false; } } //ClassAnnotation if (!readClassAnnotation(jsonret["annotation"])) return false; //SuperClassDesc ??? if (!readClassDesc(jsonret["superclass"])) return false; //更新refs updateObjectRef(refindex, TC_CLASSDESC, jsonret); return true; } bool readNewProxyClassDesc(Json::Value& jsonret) { //由于desc很长很长,先占个坑把ref的index占了 uint32_t refindex = setObjectRef(TC_PROXYCLASSDESC, jsonret); uint32_t count; if (!m_bufstream->read_data(count)) return false; count = _bswap_32(count); //proxyInterfaceNames for (uint32_t i = 0; i < count; i++) { std::string classname; if (!readUtf(classname)) return false; jsonret["proxyclass"][i] = classname; } //ClassAnnotation if (!readClassAnnotation(jsonret["annotation"])) return false; //SuperClassDesc ??? if (!readClassDesc(jsonret["superclass"])) return false; //更新refs updateObjectRef(refindex, TC_PROXYCLASSDESC, jsonret); return true; } //读取class的描述信息 bool readClassDesc(Json::Value& jsonClassDesc) { uint8_t t; if (!m_bufstream->read_data(t)) return false; if (t == TC_CLASSDESC || t == TC_PROXYCLASSDESC || t == TC_REFERENCE || t == TC_NULL) return readContentElement(t, jsonClassDesc); return false; } bool readClassData(const Json::Value& classDesc, Json::Value& jsonret) { //通过遍历递归的手法 让superclass排到读取的前面去 if (classDesc["superclass"].isObject() && classDesc["superclass"]["classname"].isString()) { //递归走起 if (!readClassData(classDesc["superclass"], jsonret["_super"])) return false; } //搞自己的吧 //仅支持标准TC_CLASSDESC TC_PROXYCLASSDESC暂无数据没办法测试研究。。。 assert(classDesc["classname"].isString()); assert(classDesc["fields"].isArray()); assert(classDesc["flags"].isInt()); if (!classDesc["classname"].isString()) { printf("Error:no class name.\n"); return false; } if (!classDesc["fields"].isArray()) { printf("Error:no fields.\n"); return false; } if (!classDesc["flags"].isInt()) { printf("Error:no flags.\n"); return false; } int flags = classDesc["flags"].asInt(); jsonret["_desc"] = classDesc; if (flags & SC_SERIALIZABLE) { //读取字段数据 size_t fieldscount = classDesc["fields"].size(); for (size_t i = 0; i < fieldscount; i++) { const Json::Value& jsonField = classDesc["fields"][i]; if (!readFieldValue(jsonField["type"].asInt(), jsonret["_data"][jsonField["name"].asString()])) return false; } } bool hasBlockData = false; if ((flags & SC_SERIALIZABLE) && (flags & SC_WRITE_METHOD)) hasBlockData = true; if (flags & SC_EXTERNALIZABLE) { if (flags & SC_BLOCK_DATA) { hasBlockData = true; } else { printf("Unable to parse externalContents for protocol version 1.\n"); return false; } } if (hasBlockData) { if (!readClassAnnotation(jsonret["_block"])) return false; } //额外处理几种类型的显示 //"java.util.HashMap" if (classDesc["classname"].asString() == "java.util.HashMap" && jsonret["_block"].isArray()) { jsonret["_hashmap"].resize(0); //hashmap 在block里面第0个疑似是hashmap的size(),直接无视,解析内容 //内容是size;key-value;key-value;key-value; size_t blockcount = jsonret["_block"].size(); if (blockcount % 2) //第一块是size 后面是kv对 { size_t kvcount = blockcount / 2; //printf("Hashmap size: %d\n", kvcount); for (size_t i = 0; i < kvcount; i++) { //key Json::Value key; const Json::Value& keytmp = jsonret["_block"][i * 2 + 1]; if (keytmp.isObject() && keytmp["_data"].isObject() && !keytmp["_data"]["value"].isNull()) key = keytmp["_data"]["value"]; else key = keytmp; //value const Json::Value& valuetmp = jsonret["_block"][i * 2 + 2]; if (valuetmp.isObject() && valuetmp["_data"].isObject() && !valuetmp["_data"]["value"].isNull()) jsonret["_hashmap"][i][key.asString()] = valuetmp["_data"]["value"]; else jsonret["_hashmap"][i][key.asString()] = valuetmp; #ifdef _DEBUG //printf("key:%s, value:%s\n", Json2String(key).c_str(), Json2String(jsonret["_hashmap"][i][key.asString()]).c_str()); #endif // _DEBUG } } } //java.util.ArrayList if (classDesc["classname"].asString() == "java.util.ArrayList" && jsonret["_block"].isArray()) { jsonret["_array"].resize(0); //_data里面有一个"size": 1表示的就是size //blockdata里面第一个元素应该也是长度,直接无视,读取所有blockdata size_t blockcount = jsonret["_block"].size(); if (blockcount > 1) { blockcount--; //将第一个元素去掉 for (size_t i = 0; i < blockcount; i++) { Json::Value& datatmp = jsonret["_block"][i + 1]; if (datatmp.isObject() && !datatmp["_data"].isNull()) jsonret["_array"][i] = datatmp["_data"]; else jsonret["_array"][i] = datatmp; } } } //其他的类型待补充 //... return true; } bool readNewObject(Json::Value& jsonret) { //printf("TC_OBJECT\n"); //读取类描述 Json::Value classDesc; if (!readClassDesc(classDesc)) return false; //这中间要让索引值加1 uint32_t refindex = setObjectRef(TC_OBJECT, jsonret); //读取值 if (!readClassData(classDesc, jsonret)) return false; //更新值 updateObjectRef(refindex, TC_OBJECT, jsonret); return true; } bool readNewClass(Json::Value& jsonret) { //printf("TC_CLASS\n"); Json::Value classDesc; if (!readClassDesc(classDesc)) return false; assert(classDesc["classname"].isString()); if (!classDesc["classname"].isString()) { //printf("Error:no class name.\n"); return false; } jsonret["_desc"] = classDesc; //增加引用 不知道还能干啥 m_refIndex++; return true; } bool readNewEnum(Json::Value& jsonret) { //printf("TC_ENUM\n"); Json::Value classDesc; if (!readClassDesc(classDesc)) return false; assert(classDesc["classname"].isString()); if (!classDesc["classname"].isString()) { printf("Error:no class name.\n"); return false; } //先增加引用 int refindex = setObjectRef(TC_ENUM, jsonret); jsonret["_desc"] = classDesc; //enumConstantName ??? if (!readNewString(jsonret["_enum"])) return false; //更新引用的值 updateObjectRef(refindex, TC_ENUM, jsonret); return true; } bool readBlockData(Json::Value& jsonret) { //printf("TC_BLOCKDATA\n"); uint8_t len; if (!m_bufstream->read_data(len)) return false; if (len) { std::string block; if (!m_bufstream->read_buffer(block, len)) return false; jsonret = tohex(block); } else { jsonret = ""; } return true; } bool readBlockDataLong(Json::Value& jsonret) { //printf("TC_BLOCKDATALONG\n"); uint32_t len; if (!m_bufstream->read_data(len)) return false; len = _bswap_32(len); if (len) { std::string block; if (!m_bufstream->read_buffer(block, len)) return false; jsonret = tohex(block); } else { jsonret = ""; } return true; } bool readContentElement(uint8_t type, Json::Value& jsonret) { switch (type) { case TC_OBJECT: if (!readNewObject(jsonret)) return false; break; case TC_CLASS: if (!readNewClass(jsonret)) return false; break; case TC_ARRAY: if (!readNewArray(jsonret)) return false; break; case TC_STRING: { std::string val; if (!readUtf(val)) return false; jsonret = val; setObjectRef(TC_STRING, jsonret); break; } case TC_LONGSTRING: { std::string val; if (!readLongUtf(val)) return false; jsonret = val; setObjectRef(TC_STRING, jsonret); break; } case TC_ENUM: if (!readNewEnum(jsonret)) return false; break; case TC_CLASSDESC: if (!readNewClassDesc(jsonret)) return false; break; case TC_PROXYCLASSDESC: if (!readNewProxyClassDesc(jsonret)) return false; break; case TC_REFERENCE: uint32_t ref; if (!readReference(ref)) return false; jsonret = getObjectByRef(ref); break; case TC_NULL: jsonret = NULL; break; // case TC_EXCEPTION: // printf("TC_EXCEPTION\n"); // break; // case TC_RESET: // printf("TC_RESET\n"); // break; case TC_BLOCKDATA: if (!readBlockData(jsonret)) return false; break; case TC_BLOCKDATALONG: if (!readBlockDataLong(jsonret)) return false; break; default: printf("Unknown type - %x\n", type); break; } return true; } bool readContentElement(Json::Value& jsonret) { uint8_t t; if (!m_bufstream->read_data(t)) return false; return readContentElement(t, jsonret); } bool JavaSerializationParser(Json::Value& jsonret) { uint8_t b1, b2; //读取文件头 if (!m_bufstream->read_data(b1)) return false; if (b1 != 0xac) { switch (b1) { case 0x50: printf("RMI Call - 0x50 \n"); break; case 0x51: printf("RMI ReturnData - 0x51 \n"); break; case 0x52: printf("RMI Ping - 0x52 \n"); break; case 0x53: printf("RMI PingAck - 0x53 \n"); break; case 0x54: printf("RMI DgcAck - 0x54 \n"); break; default: printf("Unknown RMI packet type - 0x%x \n" + b1); break; } //不是0xac开头的 再读取一次 if (!m_bufstream->read_data(b1)) return false; } if (!m_bufstream->read_data(b2)) return false; //校验文件头 printf("STREAM_MAGIC - %x %x\n", b1, b2); if (b1 != 0xac || b2 != 0xed) { printf("Invalid STREAM_MAGIC, should be ac ed \n"); return false; } //校验版本 if (!m_bufstream->read_data(b1)) return false; if (!m_bufstream->read_data(b2)) return false; printf("STREAM_VERSION - %x %x\n", b1, b2); if (b1 != 0x00 || b2 != 0x05) { printf("Invalid STREAM_VERSION, should be 00 05 \n"); return false; } //解析内容了 int index = 0; while (true) { Json::Value value; if (!readContentElement(value)) { if (!value.isNull()) { if (index == 0) jsonret = value; else jsonret[index] = value; return false; } } if (m_bufstream->eof()) break; //后面还有 jsonret[index] = value; index++; } return true; } }; /* //实例1 普通的对象 使用_data { "_data": { "B_points": 0, "account_desc": "E会员", "account_level": 5, "android_url": "", "auth_token": "GgMBu55DmpL8hm7HNRsg", "avatar": "https://ugc.bthhotels.com/avatar/images/default_avatar.png!a160", "balance": 0, "birth": "1995/01/12", "btn_text": "", "can_update_avatar": false, "carbon_points": 0, "card_balance": "0", "card_code": "", "code": "100000138749707", "ctf_code": "412702199601028052", "ctf_type": "ID", "desc": "", "down_days_left": 0, "down_expire_date": "2023-04-08", "email": "", "gift_switch": true, "growth_value": 0, "keep_level_growth_value": 0, "keep_level_score": "", "level_up_growth_value": 1000, "lvl_exp_text": "", "name": "张三", "new_balance": "0", "new_red_packet": "0", "next_account_desc": "银会员", "next_level_nights": 3, "nights": 0, "phone": "136****7271", "points": 0, "red_packet": 0, "score_speed_times": 1.0, "tags": "[\"SL01\",\"E06\"]", "title": "", "user_markers": "[]" }, "_desc": { "annotation": null, "classname": "com.ziipin.homeinn.model.UserInfo", "fields": [ { "name": "B_points", "type": 73 }, { "name": "account_level", "type": 73 }, { "name": "balance", "type": 73 }, { "name": "can_update_avatar", "type": 90 }, { "name": "carbon_points", "type": 73 }, { "name": "down_days_left", "type": 73 }, { "name": "gift_switch", "type": 90 }, { "name": "growth_value", "type": 73 }, { "name": "keep_level_growth_value", "type": 73 }, { "name": "level_up_growth_value", "type": 73 }, { "name": "next_level_nights", "type": 73 }, { "name": "nights", "type": 73 }, { "name": "points", "type": 73 }, { "name": "red_packet", "type": 73 }, { "name": "score_speed_times", "type": 70 }, { "classname": "Ljava/lang/String;", "name": "account_desc", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "android_url", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "auth_token", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "avatar", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "birth", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "btn_text", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "card_balance", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "card_code", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "code", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "ctf_code", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "ctf_type", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "desc", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "down_expire_date", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "email", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "keep_level_score", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "lvl_exp_text", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "name", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "new_balance", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "new_red_packet", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "next_account_desc", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "phone", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "tags", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "title", "type": 76 }, { "classname": "Ljava/lang/String;", "name": "user_markers", "type": 76 }], "flags": 2, "superclass": 0, "uid": "fb74abdfc6ffaf03" } } 实例2:hashmap类的解析,看_hashmap字段 { "_block": [ "0000000800000005", { "_data": { "value": 98305 }, "_desc": { "annotation": null, "classname": "java.lang.Integer", "fields": [ { "name": "value", "type": 73 } ], "flags": 2, "superclass": { "annotation": null, "classname": "java.lang.Number", "fields": [], "flags": 2, "superclass": 0, "uid": "86ac951d0b94e08b" }, "uid": "12e2a0a4f7818738" }, "_super": { "_desc": { "annotation": null, "classname": "java.lang.Number", "fields": [], "flags": 2, "superclass": 0, "uid": "86ac951d0b94e08b" } } }, { "_data": { "value": true }, "_desc": { "annotation": null, "classname": "java.lang.Boolean", "fields": [ { "name": "value", "type": 90 } ], "flags": 2, "superclass": 0, "uid": "cd207280d59cfaee" } }, { "_data": { "value": 256 }, "_desc": { "annotation": null, "classname": "java.lang.Integer", "fields": [ { "name": "value", "type": 73 } ], "flags": 2, "superclass": { "annotation": null, "classname": "java.lang.Number", "fields": [], "flags": 2, "superclass": 0, "uid": "86ac951d0b94e08b" }, "uid": "12e2a0a4f7818738" }, "_super": { "_desc": { "annotation": null, "classname": "java.lang.Number", "fields": [], "flags": 2, "superclass": 0, "uid": "86ac951d0b94e08b" } } }, "A86880902494769", { "_data": { "value": 259 }, "_desc": { "annotation": null, "classname": "java.lang.Integer", "fields": [ { "name": "value", "type": 73 } ], "flags": 2, "superclass": { "annotation": null, "classname": "java.lang.Number", "fields": [], "flags": 2, "superclass": 0, "uid": "86ac951d0b94e08b" }, "uid": "12e2a0a4f7818738" }, "_super": { "_desc": { "annotation": null, "classname": "java.lang.Number", "fields": [], "flags": 2, "superclass": 0, "uid": "86ac951d0b94e08b" } } }, "OPPOOPPO R7sPlus: fp asimd evtstrm aes pmull sha1 sha2 crc32: AArch64 Processor rev 4 (aarch64): 8: Qualcomm Technologies, Inc MSM8939: null", { "_data": { "value": 94209 }, "_desc": { "annotation": null, "classname": "java.lang.Integer", "fields": [ { "name": "value", "type": 73 } ], "flags": 2, "superclass": { "annotation": null, "classname": "java.lang.Number", "fields": [], "flags": 2, "superclass": 0, "uid": "86ac951d0b94e08b" }, "uid": "12e2a0a4f7818738" }, "_super": { "_desc": { "annotation": null, "classname": "java.lang.Number", "fields": [], "flags": 2, "superclass": 0, "uid": "86ac951d0b94e08b" } } }, { "_data": { "value": 0 }, "_desc": { "annotation": null, "classname": "java.lang.Integer", "fields": [ { "name": "value", "type": 73 } ], "flags": 2, "superclass": { "annotation": null, "classname": "java.lang.Number", "fields": [], "flags": 2, "superclass": 0, "uid": "86ac951d0b94e08b" }, "uid": "12e2a0a4f7818738" }, "_super": { "_desc": { "annotation": null, "classname": "java.lang.Number", "fields": [], "flags": 2, "superclass": 0, "uid": "86ac951d0b94e08b" } } }, { "_data": { "value": 258 }, "_desc": { "annotation": null, "classname": "java.lang.Integer", "fields": [ { "name": "value", "type": 73 } ], "flags": 2, "superclass": { "annotation": null, "classname": "java.lang.Number", "fields": [], "flags": 2, "superclass": 0, "uid": "86ac951d0b94e08b" }, "uid": "12e2a0a4f7818738" }, "_super": { "_desc": { "annotation": null, "classname": "java.lang.Number", "fields": [], "flags": 2, "superclass": 0, "uid": "86ac951d0b94e08b" } } }, "868809024947694" ], "_data": { "loadFactor": 0.75 }, "_desc": { "annotation": null, "classname": "java.util.HashMap", "fields": [ { "name": "loadFactor", "type": 70 } ], "flags": 3, "superclass": 0, "uid": "0507dac1c31660d1" }, "_hashmap": [ { "98305": true }, { "256": "A86880902494769" }, { "259": "OPPOOPPO R7sPlus: fp asimd evtstrm aes pmull sha1 sha2 crc32: AArch64 Processor rev 4 (aarch64): 8: Qualcomm Technologies, Inc MSM8939: null" }, { "94209": 0 }, { "258": "868809024947694" } ] } */