reproto 0.0.6__py3-none-any.whl → 0.0.8__py3-none-any.whl
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.
- .git/COMMIT_EDITMSG +1 -1
- .git/index +0 -0
- .git/logs/HEAD +3 -0
- .git/logs/refs/heads/iyue +3 -0
- .git/logs/refs/remotes/gitlab/iyue +3 -0
- .git/logs/refs/remotes/origin/iyue +3 -0
- .git/objects/15/eb3f02479e633439ec83c143e703f8448043a1 +0 -0
- .git/objects/20/cf56ec106bcd66420dd000279f983571b918b6 +0 -0
- .git/objects/21/55b64d52922c88527c102d62f23e5c2abbae79 +0 -0
- .git/objects/26/1f67f3b731b32f6d77de9dd7be2d61e2a14ace +0 -0
- .git/objects/2e/2c1c42f5ac5d665cc672d3792078b756d9ab0e +0 -0
- .git/objects/33/52dfa8f5d9eb46cc98ea7ccecf02e4d9df95f7 +0 -0
- .git/objects/35/8bace20b731ff1bbb256d2a0158dfc84720978 +0 -0
- .git/objects/3c/6f0120229cc2cd8123efbeb7f186eb0a485f29 +0 -0
- .git/objects/4d/6d457bfabc4af842e5ddc2d56eb059d5dfdc9d +0 -0
- .git/objects/55/6723fdd4f525eed41c52fa80defca3f0c81c47 +0 -0
- .git/objects/65/a4f0ada7519f8b1e6a7c7e287541b8effde9fd +0 -0
- .git/objects/76/311aa8e59d780763e0d66787067cc5d9613a67 +0 -0
- .git/objects/8c/809c42c7ae13007fd885ee7bcffae7acf2c520 +0 -0
- .git/objects/8d/44142ae2d6dbb59d4ebed8587bccd051e5766b +0 -0
- .git/objects/8d/4a5767bef0c342f1660526f9671c0944922c40 +0 -0
- .git/objects/95/295a15779ebefd563ec777c3d3cced7e8d0209 +0 -0
- .git/objects/97/56fe0931216a7c40cbf250e1ab8a6dfd589f13 +0 -0
- .git/objects/9a/e313cdf64cd82416c1238eb493e6396f799f12 +0 -0
- .git/objects/cd/2d6c229438c6b1c694b9392a85888d89ef49c1 +0 -0
- .git/objects/db/beedb30613f79ae3ff67df1428cf8ade223711 +0 -0
- .git/objects/e8/1433b6ad92206cdadbee1f474b4f99383314cb +0 -0
- .git/objects/e9/a15996cb55ac72aeb6611d26e8d22246589943 +0 -0
- .git/objects/f7/25a430eb3364460ba854dbc8809edc21dc6c70 +0 -0
- .git/objects/fc/e15b9dbffd9f37b1f2d46944ee2d0394df6565 +2 -0
- .git/refs/heads/iyue +1 -1
- .git/refs/remotes/gitlab/iyue +1 -1
- .git/refs/remotes/origin/iyue +1 -1
- README.md +36 -116
- core/info_decoder.py +512 -105
- core/reconstructor.py +645 -84
- generation/proto_generator.py +38 -12
- main.py +36 -5
- parsing/java_parser.py +81 -1
- pyproject.toml +13 -2
- {reproto-0.0.6.dist-info → reproto-0.0.8.dist-info}/METADATA +46 -119
- {reproto-0.0.6.dist-info → reproto-0.0.8.dist-info}/RECORD +46 -20
- utils/file_cache.py +165 -0
- utils/type_index.py +341 -0
- {reproto-0.0.6.dist-info → reproto-0.0.8.dist-info}/WHEEL +0 -0
- {reproto-0.0.6.dist-info → reproto-0.0.8.dist-info}/entry_points.txt +0 -0
generation/proto_generator.py
CHANGED
@@ -3,6 +3,7 @@ Protobuf文件生成器
|
|
3
3
|
|
4
4
|
根据解析出的消息定义生成标准的.proto文件
|
5
5
|
支持完整的Protobuf语法,包括包声明、导入、Java选项和消息定义
|
6
|
+
集成Google Protobuf Well-Known Types支持
|
6
7
|
|
7
8
|
Author: AI Assistant
|
8
9
|
"""
|
@@ -157,12 +158,13 @@ class ProtoGenerator:
|
|
157
158
|
"""
|
158
159
|
lines = [f'message {message_def.name} {{']
|
159
160
|
|
160
|
-
# 生成oneof
|
161
|
+
# 生成oneof字段(oneof字段内部也按tag排序)
|
161
162
|
for oneof in message_def.oneofs:
|
162
163
|
lines.extend(self._generate_oneof_definition(oneof))
|
163
164
|
|
164
|
-
#
|
165
|
-
|
165
|
+
# 生成常规字段(按tag排序)
|
166
|
+
sorted_fields = sorted(message_def.fields, key=lambda field: field.tag)
|
167
|
+
for field in sorted_fields:
|
166
168
|
lines.append(self._generate_field_definition(field))
|
167
169
|
|
168
170
|
lines.append('}')
|
@@ -180,19 +182,24 @@ class ProtoGenerator:
|
|
180
182
|
"""
|
181
183
|
lines = [f'enum {enum_def.name} {{']
|
182
184
|
|
183
|
-
#
|
184
|
-
|
185
|
+
# 生成枚举值(按value排序)
|
186
|
+
sorted_values = sorted(enum_def.values, key=lambda enum_value: enum_value.value)
|
187
|
+
for enum_value in sorted_values:
|
185
188
|
lines.append(f' {enum_value.name} = {enum_value.value};')
|
186
189
|
|
187
190
|
lines.append('}')
|
188
191
|
return lines
|
189
192
|
|
190
193
|
def _generate_oneof_definition(self, oneof) -> List[str]:
|
191
|
-
"""生成oneof
|
194
|
+
"""生成oneof字段定义(字段按tag排序)"""
|
192
195
|
lines = [f' oneof {oneof.name} {{']
|
193
|
-
|
196
|
+
|
197
|
+
# 对oneof内部的字段按tag排序
|
198
|
+
sorted_fields = sorted(oneof.fields, key=lambda field: field.tag)
|
199
|
+
for field in sorted_fields:
|
194
200
|
field_type = self._resolve_field_type(field)
|
195
201
|
lines.append(f' {field_type} {field.name} = {field.tag};')
|
202
|
+
|
196
203
|
lines.append(' }')
|
197
204
|
return lines
|
198
205
|
|
@@ -257,9 +264,13 @@ class ProtoGenerator:
|
|
257
264
|
if not field.type_name:
|
258
265
|
return None
|
259
266
|
|
260
|
-
#
|
261
|
-
|
262
|
-
|
267
|
+
# 检查基础类型
|
268
|
+
basic_proto_types = {
|
269
|
+
'string', 'int32', 'int64', 'uint32', 'uint64', 'sint32', 'sint64',
|
270
|
+
'fixed32', 'fixed64', 'sfixed32', 'sfixed64', 'bool', 'float', 'double', 'bytes'
|
271
|
+
}
|
272
|
+
|
273
|
+
if field.type_name in basic_proto_types:
|
263
274
|
return None
|
264
275
|
|
265
276
|
# 处理map类型:map<string, Contact> -> 提取值类型Contact
|
@@ -273,12 +284,17 @@ class ProtoGenerator:
|
|
273
284
|
value_type = value_type.strip()
|
274
285
|
|
275
286
|
# 只处理值类型的导入(键类型通常是基础类型)
|
276
|
-
if value_type not in
|
287
|
+
if value_type not in basic_proto_types:
|
277
288
|
full_class_name = self._resolve_full_class_name(value_type, current_package, all_messages)
|
278
289
|
if full_class_name:
|
279
290
|
return self._class_name_to_import_path(full_class_name)
|
280
291
|
return None
|
281
292
|
|
293
|
+
# 跳过通用类型标识符
|
294
|
+
generic_types = {'enum', 'message'}
|
295
|
+
if field.type_name in generic_types:
|
296
|
+
return None
|
297
|
+
|
282
298
|
# 解析完整类名
|
283
299
|
full_class_name = self._resolve_full_class_name(field.type_name, current_package, all_messages)
|
284
300
|
if full_class_name:
|
@@ -297,8 +313,18 @@ class ProtoGenerator:
|
|
297
313
|
all_messages: 所有消息定义
|
298
314
|
|
299
315
|
Returns:
|
300
|
-
|
316
|
+
完整的类名,如果是基础类型则返回None
|
301
317
|
"""
|
318
|
+
# 检查是否为基础类型
|
319
|
+
basic_types = {
|
320
|
+
'string', 'int', 'long', 'boolean', 'bool', 'float', 'double', 'bytes',
|
321
|
+
'int32', 'int64', 'uint32', 'uint64', 'sint32', 'sint64',
|
322
|
+
'fixed32', 'fixed64', 'sfixed32', 'sfixed64'
|
323
|
+
}
|
324
|
+
|
325
|
+
if type_name in basic_types:
|
326
|
+
return None
|
327
|
+
|
302
328
|
# 如果是完整的类名,直接返回
|
303
329
|
if '.' in type_name:
|
304
330
|
return type_name
|
main.py
CHANGED
@@ -132,20 +132,51 @@ def main():
|
|
132
132
|
|
133
133
|
# 创建重构器并执行
|
134
134
|
reconstructor = ProtoReconstructor(sources_dir, output_dir)
|
135
|
+
reconstructor._verbose = args.verbose # 传递verbose标志
|
135
136
|
results = reconstructor.reconstruct_from_root(root_class)
|
136
137
|
|
137
|
-
#
|
138
|
+
# 输出详细的结果统计
|
138
139
|
if results:
|
140
|
+
# 统计成功和失败的数量
|
141
|
+
success_count = len(results)
|
142
|
+
failed_count = len(reconstructor.failed_classes) if hasattr(reconstructor, 'failed_classes') else 0
|
143
|
+
total_attempted = success_count + failed_count
|
144
|
+
|
139
145
|
logger.success("✅ 重构完成!")
|
140
|
-
logger.info(f"📊 处理统计:
|
146
|
+
logger.info(f"📊 处理统计: 共尝试处理 {total_attempted} 个类型")
|
141
147
|
|
142
148
|
message_count = sum(1 for r in results.values() if hasattr(r, 'fields'))
|
143
149
|
enum_count = sum(1 for r in results.values() if hasattr(r, 'values'))
|
144
150
|
|
145
|
-
logger.info(f" -
|
146
|
-
|
151
|
+
logger.info(f" - ✅ 成功: {success_count} 个 (消息: {message_count}, 枚举: {enum_count})")
|
152
|
+
|
153
|
+
# 显示失败的类
|
154
|
+
if hasattr(reconstructor, 'failed_classes') and reconstructor.failed_classes:
|
155
|
+
logger.warning(f" - ❌ 失败: {failed_count} 个")
|
156
|
+
for failed_class, reason in reconstructor.failed_classes.items():
|
157
|
+
logger.warning(f" • {failed_class}: {reason}")
|
158
|
+
|
159
|
+
# 显示跳过的类
|
160
|
+
if hasattr(reconstructor, 'skipped_classes') and reconstructor.skipped_classes:
|
161
|
+
skipped_count = len(reconstructor.skipped_classes)
|
162
|
+
logger.info(f" - ⏭️ 跳过: {skipped_count} 个 (基础类型或已处理)")
|
163
|
+
if args.verbose:
|
164
|
+
for skipped_class, reason in reconstructor.skipped_classes.items():
|
165
|
+
logger.info(f" • {skipped_class}: {reason}")
|
147
166
|
else:
|
148
|
-
logger.
|
167
|
+
logger.error("❌ 没有生成任何proto文件!")
|
168
|
+
logger.error("请检查:")
|
169
|
+
logger.error(" 1. 根类名是否正确")
|
170
|
+
logger.error(" 2. Java源码目录是否包含对应的文件")
|
171
|
+
logger.error(" 3. 类是否为protobuf消息类")
|
172
|
+
|
173
|
+
# 显示详细的失败信息
|
174
|
+
if hasattr(reconstructor, 'failed_classes') and reconstructor.failed_classes:
|
175
|
+
logger.error("失败的类:")
|
176
|
+
for failed_class, reason in reconstructor.failed_classes.items():
|
177
|
+
logger.error(f" • {failed_class}: {reason}")
|
178
|
+
|
179
|
+
sys.exit(1)
|
149
180
|
|
150
181
|
except KeyboardInterrupt:
|
151
182
|
if args:
|
parsing/java_parser.py
CHANGED
@@ -353,4 +353,84 @@ class JavaParser:
|
|
353
353
|
# 对于非java包的类,保留完整路径以便后续处理
|
354
354
|
pass
|
355
355
|
|
356
|
-
return field_type
|
356
|
+
return field_type
|
357
|
+
|
358
|
+
def extract_field_tags(self, java_file_path: Path) -> Optional[dict]:
|
359
|
+
"""
|
360
|
+
从Java文件中提取字段标签信息
|
361
|
+
|
362
|
+
解析类似这样的常量定义:
|
363
|
+
public static final int TEXT_FIELD_NUMBER = 1;
|
364
|
+
public static final int ISFINAL_FIELD_NUMBER = 2;
|
365
|
+
|
366
|
+
Args:
|
367
|
+
java_file_path: Java文件路径
|
368
|
+
|
369
|
+
Returns:
|
370
|
+
字段标签映射 {field_name: tag} 或 None 如果解析失败
|
371
|
+
"""
|
372
|
+
try:
|
373
|
+
# 读取Java文件内容
|
374
|
+
content = java_file_path.read_text(encoding='utf-8')
|
375
|
+
|
376
|
+
# 匹配字段标签常量定义
|
377
|
+
# 格式:public static final int FIELD_NAME_FIELD_NUMBER = 数字;
|
378
|
+
field_tag_pattern = re.compile(
|
379
|
+
r'public\s+static\s+final\s+int\s+'
|
380
|
+
r'([A-Z_]+)_FIELD_NUMBER\s*=\s*(\d+)\s*;'
|
381
|
+
)
|
382
|
+
|
383
|
+
field_tags = {}
|
384
|
+
|
385
|
+
# 查找所有字段标签定义
|
386
|
+
for match in field_tag_pattern.finditer(content):
|
387
|
+
field_const_name = match.group(1) # 如 TEXT, ISFINAL
|
388
|
+
tag_value = int(match.group(2)) # 如 1, 2
|
389
|
+
|
390
|
+
# 转换常量名为字段名
|
391
|
+
# TEXT -> text_, ISFINAL -> isFinal_
|
392
|
+
field_name = self._const_name_to_field_name(field_const_name)
|
393
|
+
field_tags[field_name] = tag_value
|
394
|
+
|
395
|
+
self.logger.debug(f" 🏷️ 提取字段标签: {field_name} = {tag_value}")
|
396
|
+
|
397
|
+
return field_tags if field_tags else None
|
398
|
+
|
399
|
+
except Exception as e:
|
400
|
+
self.logger.error(f"❌ 提取字段标签失败 {java_file_path}: {e}")
|
401
|
+
return None
|
402
|
+
|
403
|
+
def _const_name_to_field_name(self, const_name: str) -> str:
|
404
|
+
"""
|
405
|
+
将常量名转换为字段名
|
406
|
+
|
407
|
+
Args:
|
408
|
+
const_name: 常量名(如 TEXT, ISFINAL, PAYLOADTYPE, USERID, INSTALLATIONID)
|
409
|
+
|
410
|
+
Returns:
|
411
|
+
字段名(如 text_, isFinal_, payloadType_, userId_, installationId_)
|
412
|
+
"""
|
413
|
+
# 特殊处理一些常见模式
|
414
|
+
special_cases = {
|
415
|
+
'ISFINAL': 'isFinal',
|
416
|
+
'PAYLOADTYPE': 'payloadType',
|
417
|
+
'TERMINATIONREASON': 'terminationReason',
|
418
|
+
'USERID': 'userId',
|
419
|
+
'INSTALLATIONID': 'installationId',
|
420
|
+
'PHONENUMBER': 'phoneNumber',
|
421
|
+
'COUNTRYCODE': 'countryCode',
|
422
|
+
}
|
423
|
+
|
424
|
+
if const_name in special_cases:
|
425
|
+
return special_cases[const_name] + '_'
|
426
|
+
|
427
|
+
# 通用转换:将UPPER_CASE转换为camelCase
|
428
|
+
if '_' in const_name:
|
429
|
+
# 处理下划线分隔的常量名
|
430
|
+
parts = const_name.lower().split('_')
|
431
|
+
field_name = parts[0] + ''.join(word.capitalize() for word in parts[1:])
|
432
|
+
else:
|
433
|
+
# 处理单个单词的常量名
|
434
|
+
field_name = const_name.lower()
|
435
|
+
|
436
|
+
return field_name + '_'
|
pyproject.toml
CHANGED
@@ -4,11 +4,22 @@ build-backend = "poetry.core.masonry.api"
|
|
4
4
|
|
5
5
|
[tool.poetry]
|
6
6
|
name = "reproto"
|
7
|
-
version = "0.0.
|
7
|
+
version = "0.0.8"
|
8
8
|
description = "一个强大的逆向工程工具, 能够从任何使用Google Protobuf Lite的Android应用中自动重构出完整的.proto文件结构."
|
9
9
|
readme = "README.md"
|
10
|
-
license = "
|
10
|
+
license = "Proprietary"
|
11
11
|
authors = ["iyue <ys1231@126.com>"]
|
12
|
+
homepage = "https://github.com/ys1231/reproto"
|
13
|
+
repository = "https://github.com/ys1231/reproto.git"
|
14
|
+
keywords = ["protobuf", "reverse-engineering", "android", "jadx", "proto"]
|
15
|
+
classifiers = [
|
16
|
+
"Development Status :: 4 - Beta",
|
17
|
+
"Intended Audience :: Developers",
|
18
|
+
"Topic :: Software Development :: Code Generators",
|
19
|
+
"Topic :: Software Development :: Disassemblers",
|
20
|
+
"Programming Language :: Python :: 3",
|
21
|
+
"Programming Language :: Python :: 3.12",
|
22
|
+
]
|
12
23
|
# 从当前目录自动包含所有包
|
13
24
|
packages = [
|
14
25
|
{include = "*", from = "."}
|
@@ -1,16 +1,23 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: reproto
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.8
|
4
4
|
Summary: 一个强大的逆向工程工具, 能够从任何使用Google Protobuf Lite的Android应用中自动重构出完整的.proto文件结构.
|
5
|
-
License:
|
5
|
+
License: Proprietary
|
6
|
+
Keywords: protobuf,reverse-engineering,android,jadx,proto
|
6
7
|
Author: iyue
|
7
8
|
Author-email: ys1231@126.com
|
8
9
|
Requires-Python: >=3.12,<4.0
|
9
|
-
Classifier:
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
11
|
+
Classifier: Intended Audience :: Developers
|
12
|
+
Classifier: License :: Other/Proprietary License
|
10
13
|
Classifier: Programming Language :: Python :: 3
|
11
14
|
Classifier: Programming Language :: Python :: 3.12
|
12
15
|
Classifier: Programming Language :: Python :: 3.13
|
16
|
+
Classifier: Topic :: Software Development :: Code Generators
|
17
|
+
Classifier: Topic :: Software Development :: Disassemblers
|
13
18
|
Requires-Dist: loguru (>=0.7.3)
|
19
|
+
Project-URL: Homepage, https://github.com/ys1231/reproto
|
20
|
+
Project-URL: Repository, https://github.com/ys1231/reproto.git
|
14
21
|
Description-Content-Type: text/markdown
|
15
22
|
|
16
23
|
# Protobuf Reconstructor
|
@@ -25,64 +32,40 @@ Description-Content-Type: text/markdown
|
|
25
32
|
- 🔄 **递归依赖**: 自动发现和处理所有依赖的消息和枚举类型
|
26
33
|
- 📦 **完整支持**: 支持oneof、repeated、map、枚举等所有Protobuf特性
|
27
34
|
- 🌐 **通用性**: 适用于任何Android应用,无需硬编码映射
|
28
|
-
-
|
29
|
-
- 🧠 **智能推断**: 从Java源码直接读取类型信息,确保100%准确性
|
35
|
+
- 🧠 **智能推断**: 从Java源码直接读取类型信息,确保高准确性
|
30
36
|
- 📝 **标准输出**: 严格遵循Google Proto Style Guide
|
31
|
-
- 📊 **结构化日志**: 基于loguru的专业日志系统
|
32
37
|
|
33
38
|
## 🛠️ 安装
|
34
39
|
|
35
|
-
### 方法1:直接运行
|
36
40
|
```bash
|
37
41
|
# 克隆项目
|
38
|
-
git clone
|
42
|
+
git clone https://github.com/ys1231/reproto.git
|
39
43
|
cd reproto
|
40
44
|
|
41
45
|
# 安装依赖
|
42
46
|
pip install -r requirements.txt
|
43
|
-
|
44
|
-
# 运行
|
45
|
-
python main.py <java_sources_dir> <root_class> <output_dir>
|
46
|
-
```
|
47
|
-
|
48
|
-
### 方法2:安装为包
|
49
|
-
```bash
|
50
|
-
# 安装到系统
|
51
|
-
pip install -e .
|
52
|
-
|
53
|
-
# 使用命令行工具
|
54
|
-
reproto <java_sources_dir> <root_class> <output_dir>
|
55
47
|
```
|
56
48
|
|
57
49
|
## 📖 使用方法
|
58
50
|
|
59
51
|
### 基本用法
|
60
52
|
```bash
|
61
|
-
python main.py
|
62
|
-
```
|
63
|
-
|
64
|
-
### 完整参数
|
65
|
-
```bash
|
66
|
-
python main.py <java_sources_dir> <root_class> <output_dir> [--log-dir LOG_DIR] [--help]
|
53
|
+
python main.py <java_sources_dir> <root_class> <output_dir> [--verbose]
|
67
54
|
```
|
68
55
|
|
69
56
|
### 参数说明
|
70
57
|
- `java_sources_dir`: JADX反编译的Java源码目录路径
|
71
58
|
- `root_class`: 要重构的根类完整类名(如:com.example.Model)
|
72
59
|
- `output_dir`: 生成的proto文件输出目录路径
|
73
|
-
- `--
|
74
|
-
- `--help`: 显示帮助信息
|
60
|
+
- `--verbose`: 显示详细处理信息
|
75
61
|
|
76
62
|
### 示例
|
77
63
|
```bash
|
78
|
-
#
|
79
|
-
python main.py ./out_jadx/sources com.example.messaging.v1.models.MessageData ./protos_generated
|
80
|
-
|
81
|
-
# 指定日志目录
|
82
|
-
python main.py ./out_jadx/sources com.example.Model ./output --log-dir ./my_logs
|
64
|
+
# 重构消息应用的数据模型
|
65
|
+
python main.py ./out_jadx/sources com.example.messaging.v1.models.MessageData ./protos_generated --verbose
|
83
66
|
|
84
|
-
#
|
85
|
-
python main.py /
|
67
|
+
# 重构内部类
|
68
|
+
python main.py ./out_jadx/sources 'com.truecaller.accountonboarding.v1.Models$Onboarded' ./output --verbose
|
86
69
|
```
|
87
70
|
|
88
71
|
## 🔍 工作原理
|
@@ -92,7 +75,6 @@ python main.py /path/to/jadx/sources com.myapp.data.UserProfile ./output
|
|
92
75
|
2. **依赖发现**: 递归分析Java文件中的类型引用
|
93
76
|
3. **智能推断**: 基于字段名和对象数组推断枚举和消息类型
|
94
77
|
4. **源码分析**: 直接从Java源码读取真实的字段类型声明
|
95
|
-
5. **标准生成**: 生成符合Protobuf规范的.proto文件
|
96
78
|
|
97
79
|
### 解析流程
|
98
80
|
```
|
@@ -113,22 +95,17 @@ reproto/
|
|
113
95
|
├── generation/ # 生成模块
|
114
96
|
│ └── proto_generator.py # Proto文件生成器
|
115
97
|
├── models/ # 数据模型
|
116
|
-
|
98
|
+
└── utils/ # 工具函数
|
117
99
|
```
|
118
100
|
|
119
|
-
##
|
120
|
-
|
121
|
-
1. 使用JADX反编译Android应用
|
122
|
-
2. 运行ReProto指定根Protobuf类
|
123
|
-
3. 自动解析所有相关类和依赖
|
124
|
-
4. 生成完整的.proto文件结构
|
125
|
-
|
126
|
-
## 输出示例
|
101
|
+
## 📊 输出示例
|
127
102
|
|
128
103
|
### 输入:Java源码
|
129
|
-
|
130
104
|
```java
|
131
105
|
public final class MessageData extends GeneratedMessageLite {
|
106
|
+
public static final int TEXT_MESSAGE_FIELD_NUMBER = 1;
|
107
|
+
public static final int MEDIA_MESSAGE_FIELD_NUMBER = 2;
|
108
|
+
|
132
109
|
private int dataCase_;
|
133
110
|
private Object data_;
|
134
111
|
|
@@ -136,28 +113,16 @@ public final class MessageData extends GeneratedMessageLite {
|
|
136
113
|
TEXT_MESSAGE(1),
|
137
114
|
MEDIA_MESSAGE(2),
|
138
115
|
DATA_NOT_SET(0);
|
139
|
-
|
140
|
-
private final int value;
|
141
|
-
|
142
|
-
private DataCase(int value) {
|
143
|
-
this.value = value;
|
144
|
-
}
|
145
116
|
}
|
146
|
-
|
147
|
-
// 其他方法...
|
148
117
|
}
|
149
118
|
```
|
150
119
|
|
151
120
|
### 输出:Proto文件
|
152
|
-
|
153
121
|
```protobuf
|
154
122
|
syntax = "proto3";
|
155
123
|
|
156
124
|
package com.example.messaging.v1.models;
|
157
125
|
|
158
|
-
import "com/example/messaging/v1/models/message_data.proto";
|
159
|
-
import "com/example/messaging/v1/models/conversation_data.proto";
|
160
|
-
|
161
126
|
option java_package = "com.example.messaging.v1.models";
|
162
127
|
option java_multiple_files = true;
|
163
128
|
|
@@ -169,79 +134,41 @@ message MessageData {
|
|
169
134
|
}
|
170
135
|
```
|
171
136
|
|
172
|
-
##
|
173
|
-
|
174
|
-
### 使用Poetry
|
175
|
-
|
176
|
-
```bash
|
177
|
-
# 安装Poetry
|
178
|
-
curl -sSL https://install.python-poetry.org | python3 -
|
179
|
-
|
180
|
-
# 安装项目依赖
|
181
|
-
poetry install
|
182
|
-
|
183
|
-
# 进入虚拟环境
|
184
|
-
poetry shell
|
185
|
-
```
|
186
|
-
|
187
|
-
## 项目结构
|
137
|
+
## 🚀 工作流程
|
188
138
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
├── generation/ # Proto文件生成
|
194
|
-
├── models/ # 数据模型定义
|
195
|
-
├── utils/ # 工具函数
|
196
|
-
└── main.py # 入口点
|
197
|
-
```
|
139
|
+
1. 使用JADX反编译Android应用:`jadx -d out_jadx app.apk`
|
140
|
+
2. 运行ReProto指定根Protobuf类
|
141
|
+
3. 自动解析所有相关类和依赖
|
142
|
+
4. 生成完整的.proto文件结构
|
198
143
|
|
199
|
-
##
|
144
|
+
## 📝 配置选项
|
200
145
|
|
201
146
|
### 日志配置
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
# 日志文件格式: reproto-YYYY-MM-DD-HH-MM-SS.log
|
207
|
-
# 例如: reproto-2024-01-15-14-30-25.log
|
208
|
-
```
|
147
|
+
- 日志文件自动保存到 `./logs/` 目录
|
148
|
+
- 文件格式: `reproto-YYYY-MM-DD-HH-MM-SS.log`
|
149
|
+
- 使用 `--verbose` 参数查看详细处理过程
|
209
150
|
|
210
151
|
### 输出格式
|
211
152
|
生成的proto文件遵循Google Protobuf Style Guide:
|
212
|
-
-
|
213
|
-
-
|
214
|
-
-
|
215
|
-
-
|
216
|
-
- 正确的包结构和导入语句
|
217
|
-
|
218
|
-
## 🏗️ 架构设计
|
219
|
-
|
220
|
-
本项目采用模块化设计,详细的架构说明请参考 [ARCHITECTURE.md](./ARCHITECTURE.md)。
|
221
|
-
|
222
|
-
核心模块:
|
223
|
-
- **Core Layer**: 主协调器 + 字节码解码器
|
224
|
-
- **Parsing Layer**: Java解析器 + 源码分析器
|
225
|
-
- **Generation Layer**: Proto文件生成器
|
226
|
-
- **Model Layer**: 数据定义模型
|
227
|
-
- **Utility Layer**: 日志系统 + 文件工具
|
153
|
+
- 文件名:`snake_case.proto`
|
154
|
+
- 字段名:`snake_case`
|
155
|
+
- 消息名:`PascalCase`
|
156
|
+
- 枚举值:`UPPER_SNAKE_CASE`
|
228
157
|
|
158
|
+
## 🔧 开发
|
229
159
|
|
230
|
-
|
231
|
-
|
232
|
-
|
160
|
+
```bash
|
161
|
+
# 使用Poetry管理依赖
|
162
|
+
poetry install
|
163
|
+
poetry shell
|
233
164
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
- 编写单元测试
|
238
|
-
- 更新文档
|
165
|
+
# 运行测试
|
166
|
+
python main.py ../out_jadx/sources 'com.example.TestClass' ../test_output --verbose
|
167
|
+
```
|
239
168
|
|
240
|
-
##
|
169
|
+
## 📄 许可证
|
241
170
|
|
242
|
-
|
243
|
-
- JADX项目提供的反编译工具
|
244
|
-
- 逆向工程社区的技术支持
|
171
|
+
本项目为私有项目,仅供授权用户使用。
|
245
172
|
|
246
173
|
---
|
247
174
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
.git/COMMIT_EDITMSG,sha256=
|
1
|
+
.git/COMMIT_EDITMSG,sha256=OJTijUraf8zRGEsGyQ_Q3EFxeT206AEhvBZe9ph_cdI,28
|
2
2
|
.git/HEAD,sha256=ly8yuQLWQE8njkYAapHLPJ1xVg6_fMgQjCoHqKvFIdw,21
|
3
3
|
.git/config,sha256=9ZAySfDWBdI-K9eOXyrEQOhiX68AiaP0Z4CLzH07H10,399
|
4
4
|
.git/description,sha256=hatsFj1DoX6pz3eIMIvKFGbxsKjRzJLibpv2PaQGKu4,73
|
@@ -16,60 +16,86 @@
|
|
16
16
|
.git/hooks/push-to-checkout.sample,sha256=pT0HQXmLKHxt16-mSu5HPzBeZdP0lGO7nXQI7DsSv18,2783
|
17
17
|
.git/hooks/sendemail-validate.sample,sha256=ROv8kj3FRmvACWAvDs8Ge5xlRZq_6IaN3Em3jmztepI,2308
|
18
18
|
.git/hooks/update.sample,sha256=jV8vqD4QPPCLV-qmdSHfkZT0XL28s32lKtWGCXoU0QY,3650
|
19
|
-
.git/index,sha256=
|
19
|
+
.git/index,sha256=B1Rzt_0WDkah8dDUat5W191JgMFWphX94SqRGFNaulo,2167
|
20
20
|
.git/info/exclude,sha256=ZnH-g7egfIky7okWTR8nk7IxgFjri5jcXAbuClo7DsE,240
|
21
|
-
.git/logs/HEAD,sha256=
|
22
|
-
.git/logs/refs/heads/iyue,sha256=
|
23
|
-
.git/logs/refs/remotes/gitlab/iyue,sha256=
|
21
|
+
.git/logs/HEAD,sha256=xX-tAof-O9a3m9JXQU75r2QrQBSxtRQ3Vj2UoNr_qxM,1057
|
22
|
+
.git/logs/refs/heads/iyue,sha256=xX-tAof-O9a3m9JXQU75r2QrQBSxtRQ3Vj2UoNr_qxM,1057
|
23
|
+
.git/logs/refs/remotes/gitlab/iyue,sha256=UPB7A4ZXzkMHpkWp5AG846jGDLEBUY_hr0fMbb4h_V0,680
|
24
24
|
.git/logs/refs/remotes/origin/HEAD,sha256=4vCPTgC0N80jhmkFXNUlYvHtGllYJkQTGZEn6LlqZgs,163
|
25
|
-
.git/logs/refs/remotes/origin/iyue,sha256=
|
25
|
+
.git/logs/refs/remotes/origin/iyue,sha256=J3u7O9zrNOAvsYpwKq0BCIPq1sDWaw7mTbhPD-tAxog,680
|
26
26
|
.git/objects/09/a92517fe9eeb33d2fd7c979e01d163665f7abc,sha256=wyFL5jJ16f0xCpL1MB5EiJvs2opieE0hMEmyDpUV3ps,9356
|
27
27
|
.git/objects/14/d323d58fb90c209a730c17e23fd82a6c735fc1,sha256=rTCuhPM5LYusLIMDv7CLC557SlRFvvbBzgr4jwrjMVg,426
|
28
|
+
.git/objects/15/eb3f02479e633439ec83c143e703f8448043a1,sha256=duJXtvq_NNhYKG7WdejXgoMlyHIaCUG5jv9SJpU_orc,14711
|
28
29
|
.git/objects/18/89a4fb55eb3abdc528ce87f0cea039278c06fd,sha256=Uz8TPtDNnPWR5pfsIx7tMDCDFBdWLIkaPcnYPIJ12oM,2880
|
30
|
+
.git/objects/20/cf56ec106bcd66420dd000279f983571b918b6,sha256=0dwZwG7CpR7yYYNvgYDxHLPj2P7eRLK7fTW_En419pk,166
|
31
|
+
.git/objects/21/55b64d52922c88527c102d62f23e5c2abbae79,sha256=6LLW2HrSfqqVwvO59yc-EcUp6MHw6zfHwu8TB775dII,13853
|
29
32
|
.git/objects/23/bfbca38e177bcbb423dd782c35b19d127a5ab0,sha256=hYW2b3t3bVGNh4pqyyA7DMlyF4LfNZco5NwedWMwwuI,3700
|
33
|
+
.git/objects/26/1f67f3b731b32f6d77de9dd7be2d61e2a14ace,sha256=mcasCBpCulVy2N-X_d2hg8567PdhZRof4ea5nYoelJM,96
|
34
|
+
.git/objects/2e/2c1c42f5ac5d665cc672d3792078b756d9ab0e,sha256=5LG3jHGORJeswNw0lz5dc6QSsxztyMstbRDADhZDnZY,166
|
30
35
|
.git/objects/33/181441ab38eded005db356da89b54c7d29f452,sha256=iIM6a2aGs_TGZjxHKnkYYyZj_hA77nAF7r2lMOtN1VA,2021
|
36
|
+
.git/objects/33/52dfa8f5d9eb46cc98ea7ccecf02e4d9df95f7,sha256=KNAvQNdSalt8CxCZVVb8e6KBC4zqVtusT5MriFLPbIQ,4409
|
37
|
+
.git/objects/35/8bace20b731ff1bbb256d2a0158dfc84720978,sha256=hEPGT0bRzT1GlXErWRWJ7ogflTWj3SutlHRKCBH1TII,426
|
38
|
+
.git/objects/3c/6f0120229cc2cd8123efbeb7f186eb0a485f29,sha256=iyh7Xt-m7vou3slm58k8xSl3Cn2yYXTuv5WziSWHrW0,802
|
31
39
|
.git/objects/40/84f4567d983a977c49598b7d886e46b13ff50b,sha256=R3w6EvxpJRcVuJvbCslrGDK07kcOjECGGosj5tO-JBo,426
|
32
40
|
.git/objects/48/369b05749e384be9be58e5f943f3a0040d0f37,sha256=KP9dXx-XniZuIEXESlrL_MWWi55zGiFr7xtmp3oD67o,8551
|
41
|
+
.git/objects/4d/6d457bfabc4af842e5ddc2d56eb059d5dfdc9d,sha256=HLQ8aGvln8ZuhdINhhbr_aTt2BttkJOY8k6LhciAMLE,672
|
42
|
+
.git/objects/55/6723fdd4f525eed41c52fa80defca3f0c81c47,sha256=vwGNz5lxU_wrrRWVPU64TccYo4Vo4uUGC3-GwVIs1xs,4520
|
43
|
+
.git/objects/65/a4f0ada7519f8b1e6a7c7e287541b8effde9fd,sha256=jSGkVjAMcm2nrF6w_0U7lmzoBgwIJaf4P8POOlABxEQ,188
|
44
|
+
.git/objects/76/311aa8e59d780763e0d66787067cc5d9613a67,sha256=J9Xy8ESXbWUbC_4sA0KumGVKm09tzlqA8C5oJ63a_b4,2167
|
33
45
|
.git/objects/7c/00eec7ae9ef5f94fc337e5c8f9793a2a48810d,sha256=Ju-Yuy5EARcIThU4vkHrZuHQWu3MjXSZYGtBDTWR18c,96
|
46
|
+
.git/objects/8c/809c42c7ae13007fd885ee7bcffae7acf2c520,sha256=HYoU3_cZUGur3rWrgRvzHRAv0JfrXgc34R8UeGbC5Bc,14180
|
47
|
+
.git/objects/8d/44142ae2d6dbb59d4ebed8587bccd051e5766b,sha256=l1G5ZzQBQW8Lxd3WvGLRcY6quM6dBL4zdNT5ovjv3Dc,802
|
48
|
+
.git/objects/8d/4a5767bef0c342f1660526f9671c0944922c40,sha256=kP0nfEnyNmuEJ4wLQabhPPx60OIa5Dxqn7R9Ni89CqY,1900
|
49
|
+
.git/objects/95/295a15779ebefd563ec777c3d3cced7e8d0209,sha256=IIN8_K0K-3LAkUI4Ra3DS8yUsfpsqteSDGhgvRpSfZ4,426
|
50
|
+
.git/objects/97/56fe0931216a7c40cbf250e1ab8a6dfd589f13,sha256=Su7Q-bXO0K9QKEGC249NVuUS62xmQs5TgWfEmdbauaI,97
|
51
|
+
.git/objects/9a/e313cdf64cd82416c1238eb493e6396f799f12,sha256=9bPRhebwMVqtGqJUxfVq-TEUxceuOdSvicWe1H8F7Ks,876
|
34
52
|
.git/objects/a3/cedc28e563a1845a7860161b39b0fe58d5f0d3,sha256=Vee0H8dhSj4ERNDSAnRU6vebs0tbY1-lgYr1Nz5X7bc,122
|
35
53
|
.git/objects/a5/b7e4e1b63bfb65288f6553687aaabcfb4d51b1,sha256=9tl9xb48EdvQk9GIg6mEzXSwqUgD6yEVZx-sVxaQVKw,1064
|
54
|
+
.git/objects/cd/2d6c229438c6b1c694b9392a85888d89ef49c1,sha256=IW9iGk3Eb-i_Ht64HQcltVp27ziQHz5IP6k5p57YFtY,122
|
36
55
|
.git/objects/d0/9c84ad2142a187bf26a1714b7041b62e404c8f,sha256=twhhaZbfU_mgu5LIlt9ZeGjp_PT_gri_9H231H5nrNc,2172
|
37
56
|
.git/objects/d9/6d7456245232b3e159dcf691f11e51224c557a,sha256=3w45hxiT2rn6ljSdgo36fHMMWZt30r5C1FPvbnjq9tc,597
|
57
|
+
.git/objects/db/beedb30613f79ae3ff67df1428cf8ade223711,sha256=tTGayiwSvdy-uBiXQKRhNnToZ_dc1BmeXZ2mltuRfxY,3812
|
58
|
+
.git/objects/e8/1433b6ad92206cdadbee1f474b4f99383314cb,sha256=mRMdmx6wCs6b-63QL72Iutm2AUVCOIYs7J5XbAsLluc,426
|
38
59
|
.git/objects/e8/2f42ea26b8bf4f0bc92c0648ac8f190f14226d,sha256=xtbEwloZnqXdNdViAevzyprosfPQ1P--xAu6URGlaYI,155
|
60
|
+
.git/objects/e9/a15996cb55ac72aeb6611d26e8d22246589943,sha256=sTn6X3xMp3_WYpj1CmP2hDqviX86aJHTCzzi_ZTpBKw,4643
|
39
61
|
.git/objects/ed/fb5bbf938de738d1f658f80e23c675bb8b3fae,sha256=MOYiuXKTxnd9YcqU3-HUVUq2g9fPU1-AKZOQ-3xsWCk,4237
|
40
62
|
.git/objects/ef/4844af55f7f64b8dd24b81b5a8322a8c80208e,sha256=hO8yllVMOtIE4HeOvwKSqQUByH6lvaA4L-RYrSU4vlg,167
|
41
63
|
.git/objects/f2/2bfffda9fb6a7f37bed04b7c40c9466ef09454,sha256=goQNyEV3NqzS28mMXuus1SWzwb8yXnvEPef14Ugzh5Q,750
|
42
64
|
.git/objects/f5/18c69a6e1bf3052b79da01502b2837ea58f0f4,sha256=r98SFbCvw7yeAYTjzkw-2VMhOVbpm79FLZQiC5A1-pw,123
|
65
|
+
.git/objects/f7/25a430eb3364460ba854dbc8809edc21dc6c70,sha256=LdyMmAWGLWbn5G5fC7eAPi4NFOboKcJ6iJJdxENSUCk,2505
|
66
|
+
.git/objects/fc/e15b9dbffd9f37b1f2d46944ee2d0394df6565,sha256=81qdzKkVZ5C_1oej2Mm0q2RLifilVFolIs95mrUfpg4,163
|
43
67
|
.git/objects/pack/pack-289f7bb06603881c49190e6036de6390223baf77.idx,sha256=KRv1SBEe9bYL9d5V301LwPOBqFs3tMnB0dl4PriMMIw,2416
|
44
68
|
.git/objects/pack/pack-289f7bb06603881c49190e6036de6390223baf77.pack,sha256=R4oMXhr-NcPAUBXStCbAaUvGUDW_SBECmPIbiB9Gy48,42003
|
45
69
|
.git/objects/pack/pack-289f7bb06603881c49190e6036de6390223baf77.rev,sha256=22_3sqyTNB5IbwAK5oCqNz0UxDDqoZ5jcF7p_44Lalo,244
|
46
70
|
.git/packed-refs,sha256=4H0m4wd6q98wZkBk7WfvVeTBuuxQdTE65XxsswYP-oQ,112
|
47
|
-
.git/refs/heads/iyue,sha256=
|
48
|
-
.git/refs/remotes/gitlab/iyue,sha256=
|
71
|
+
.git/refs/heads/iyue,sha256=3yox20YC-z9tSZ5Qrjy3DA1_ZXUQcLCKXhdXBcw7sno,41
|
72
|
+
.git/refs/remotes/gitlab/iyue,sha256=3yox20YC-z9tSZ5Qrjy3DA1_ZXUQcLCKXhdXBcw7sno,41
|
49
73
|
.git/refs/remotes/origin/HEAD,sha256=G8pFPTbCqnJ2IkCzz9J-STqOXWU6TrlXfpt1wx5bUWE,30
|
50
|
-
.git/refs/remotes/origin/iyue,sha256=
|
74
|
+
.git/refs/remotes/origin/iyue,sha256=3yox20YC-z9tSZ5Qrjy3DA1_ZXUQcLCKXhdXBcw7sno,41
|
51
75
|
.gitignore,sha256=ThRUL1E38Z_Q4Lww0xYYl9ziFaPUvvwwqxbmp2cuwco,2068
|
52
76
|
.python-version,sha256=NxOs_9lT1XG8y-FjlRru-YinX5RcBJt_ulPwgDESZ_o,7
|
53
77
|
ARCHITECTURE.md,sha256=JALnUdREwdLRAmcUit5CGAPLpeZ6UfoYpAQkxil3NJc,8322
|
54
|
-
README.md,sha256=
|
78
|
+
README.md,sha256=1EC39Oeth4evP26KNWEMFG-hSrFNhJIAVOSSOBhc9cY,4244
|
55
79
|
core/__init__.py,sha256=ajz1GSNU9xYVrFEDSz6Xwg7amWQ_yvW75tQa1ZvRIWc,3
|
56
80
|
core/bytecode_parser.py,sha256=87ZGhnyBNGP-gRjIyRUcGfWS2HR1YA_e1OBKafLEEDc,11532
|
57
|
-
core/info_decoder.py,sha256=
|
58
|
-
core/reconstructor.py,sha256=
|
81
|
+
core/info_decoder.py,sha256=wQMZoiQ7adK1xrAhZ0GOIqeLzvf3-TO7_EAERy4EX6g,52682
|
82
|
+
core/reconstructor.py,sha256=RAA8ugrzNWg6Yc3cXu_i3ietc8aNzwh2ocGHTsEVgp8,53354
|
59
83
|
generation/__init__.py,sha256=ajz1GSNU9xYVrFEDSz6Xwg7amWQ_yvW75tQa1ZvRIWc,3
|
60
|
-
generation/proto_generator.py,sha256=
|
61
|
-
main.py,sha256=
|
84
|
+
generation/proto_generator.py,sha256=aeqKebkZ-GZAFSt2WWApC0CB3rk8iiaxYeVDm4ZD6E0,17264
|
85
|
+
main.py,sha256=3G649-aTByEjMS4tb1A9wcO9NVUxXVSvdwGTq9hXxBI,7081
|
62
86
|
models/__init__.py,sha256=WScv63rvEl65y5CWjpb6__hvjNvjpCkl6lz1Z2u0IYc,811
|
63
87
|
models/message_definition.py,sha256=AszUZnNPSBn9SMXne5ORDBiGZz1W2pcYmU8ftGC3Mks,4873
|
64
88
|
parsing/__init__.py,sha256=ajz1GSNU9xYVrFEDSz6Xwg7amWQ_yvW75tQa1ZvRIWc,3
|
65
89
|
parsing/enum_parser.py,sha256=4BjMk1NIYgt2FDZUjTZyOvFfC1uJp_MBZipVdk1tqes,6175
|
66
|
-
parsing/java_parser.py,sha256=
|
67
|
-
pyproject.toml,sha256=
|
90
|
+
parsing/java_parser.py,sha256=ECaiU9cZMNUZqoV1mrKRvaSFjZXha-lVgB59w6MuwxY,14761
|
91
|
+
pyproject.toml,sha256=U3UQ2y7O9hz_q3yMTFvBulIUdAPNroQzrVCIr4LciCc,1378
|
68
92
|
requirements.txt,sha256=cQGj3IS6Kj88jbwj_jeKkokMnG-fEezWve91mfW4CJs,96
|
69
93
|
utils/__init__.py,sha256=ajz1GSNU9xYVrFEDSz6Xwg7amWQ_yvW75tQa1ZvRIWc,3
|
94
|
+
utils/file_cache.py,sha256=eOBkfrumWg0EU1EfLESnRN1kcidi_MocxV_EWP8lEhQ,5207
|
70
95
|
utils/file_utils.py,sha256=N1Ei7hmyeOkIyZJFEXyNbtTrfeVF2hP-U8evXAVW2MA,4085
|
71
96
|
utils/logger.py,sha256=473DfzFVXzdGpiRTJGY6bBd-V5G80_P07gQqcvDChpQ,2447
|
72
|
-
|
73
|
-
reproto-0.0.
|
74
|
-
reproto-0.0.
|
75
|
-
reproto-0.0.
|
97
|
+
utils/type_index.py,sha256=So8FYyGtR0ff-ZhVHjXUdhXiXQEujlcCEJlj7OPQMsg,12128
|
98
|
+
reproto-0.0.8.dist-info/METADATA,sha256=Eo2Hrl1W_fX0u4AaPgKXk2Im_hYvu_snqG1HyTqOz_Y,5193
|
99
|
+
reproto-0.0.8.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
100
|
+
reproto-0.0.8.dist-info/entry_points.txt,sha256=6Oro9lK_2DXDgHiB3andNuIE78wxfooqacqp8yY1C-g,37
|
101
|
+
reproto-0.0.8.dist-info/RECORD,,
|