Compare commits
588
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a54464548e | ||
|
|
34563fcc9b | ||
|
|
f91b7f8009 | ||
|
|
635f673a8c | ||
|
|
e737e6c1c6 | ||
|
|
75a757d8ef | ||
|
|
25aaf89287 | ||
|
|
3787ec5f83 | ||
|
|
5d2c8c2b78 | ||
|
|
1de720e02e | ||
|
|
878da39caf | ||
|
|
80d5c8dc80 | ||
|
|
6911a609f1 | ||
|
|
907f4d99f5 | ||
|
|
6fbe67d66e | ||
|
|
5e4004c413 | ||
|
|
d1fea89e1e | ||
|
|
162b9e5863 | ||
|
|
8ad3e0ea30 | ||
|
|
7665bf0831 | ||
|
|
a8758da09b | ||
|
|
5feac72c79 | ||
|
|
4f3d486d8f | ||
|
|
1e53933786 | ||
|
|
88bb8d5fe3 | ||
|
|
2732d538e8 | ||
|
|
a8276d1289 | ||
|
|
6e324b2244 | ||
|
|
48f700ee35 | ||
|
|
37122745b6 | ||
|
|
aedd394471 | ||
|
|
78f8eca531 | ||
|
|
8f29c7ab66 | ||
|
|
693a3851ec | ||
|
|
357e354ac7 | ||
|
|
f5d791f2a1 | ||
|
|
a0c22ff012 | ||
|
|
edf7b3d32c | ||
|
|
211e3533b3 | ||
|
|
b3c912ab79 | ||
|
|
0c6fed90b7 | ||
|
|
5e4ec0fa1b | ||
|
|
8aa40e9a61 | ||
|
|
f8b65e7872 | ||
|
|
592c46b001 | ||
|
|
a496131e5a | ||
|
|
cee14e1fda | ||
|
|
92f28b2f56 | ||
|
|
ef475fcf8b | ||
|
|
39a91d4db9 | ||
|
|
d137a4cdde | ||
|
|
f8f52f205a | ||
|
|
2443b949a4 | ||
|
|
d0432d63c9 | ||
|
|
f276bcbf6c | ||
|
|
6cd3fa09b1 | ||
|
|
3e7e102a51 | ||
|
|
42e785925c | ||
|
|
d4415444c4 | ||
|
|
6fdcac6cad | ||
|
|
ccba355fa9 | ||
|
|
d78892eb4b | ||
|
|
33f90f95b6 | ||
|
|
a32d731ed7 | ||
|
|
8d8d85ba22 | ||
|
|
4526862728 | ||
|
|
6c6e2ad62b | ||
|
|
929a0a76c8 | ||
|
|
4c5fae5179 | ||
|
|
fc63fe8682 | ||
|
|
96ea32b7e4 | ||
|
|
b784912811 | ||
|
|
87fa1b613d | ||
|
|
ddd7ac7b84 | ||
|
|
f719dc46c5 | ||
|
|
9a3780229b | ||
|
|
678c4cfa68 | ||
|
|
866c72c907 | ||
|
|
7ba05210fe | ||
|
|
51e5938776 | ||
|
+12 |
169512a35b | ||
|
|
8bf882f401 | ||
|
|
9066444f6b | ||
|
|
7fbc2b5652 | ||
|
|
ecd997e512 | ||
|
|
c409a8bbe8 | ||
|
|
17cd07342d | ||
|
|
52b0a54afd | ||
|
|
7fd722e15b | ||
|
|
567b559474 | ||
|
|
607f509505 | ||
|
|
40c235c642 | ||
|
|
a06dbd509d | ||
|
|
3d24683b06 | ||
|
|
b3995a2ae5 | ||
|
|
5af154fc4b | ||
|
|
7f613149be | ||
|
|
50af8de5e8 | ||
|
|
e2efd10b70 | ||
|
|
6a34be416b | ||
|
|
b33f68deb7 | ||
|
|
60accad2de | ||
|
|
c343b787f0 | ||
|
|
6ba6aea5eb | ||
|
|
bd4f5e9c19 | ||
|
|
a718037033 | ||
|
|
1b3d57ca8a | ||
|
|
fd782cf2b1 | ||
|
|
b5dba08dba | ||
|
|
89fea8130a | ||
|
|
e8dad898da | ||
|
|
8f91e60558 | ||
|
|
c9204b96d4 | ||
|
|
f290b27299 | ||
|
|
eab61d02a1 | ||
|
|
6c1b7f86d1 | ||
|
|
98ca6c8270 | ||
|
|
99d2d7ad22 | ||
|
|
a68cfd7db0 | ||
|
|
5f702dd6cc | ||
|
|
4193bc5bf8 | ||
|
|
610966b836 | ||
|
|
2bcd7e6d13 | ||
|
|
7fd6e486ae | ||
|
|
9b598076e3 | ||
|
|
e966b9f9a5 | ||
|
|
1a430f055d | ||
|
|
529038f557 | ||
|
|
66e25e7912 | ||
|
|
ae013ad23c | ||
|
|
0f04043a5a | ||
|
|
8cd10d4727 | ||
|
|
7a93cfd118 | ||
|
|
6cb0684372 | ||
|
|
f09dde0cc9 | ||
|
|
fabb68bb9b | ||
|
|
97f6678578 | ||
|
|
72270ac275 | ||
|
|
f40bd0c4fb | ||
|
|
4f0c33e8c4 | ||
|
|
5e16e30c6b | ||
|
|
b305104e4a | ||
|
|
a8b8ff2acf | ||
|
|
5bcf71c660 | ||
|
|
c4a59101ac | ||
|
|
045c7dd63a | ||
|
|
131c1f1219 | ||
|
|
8520d425d0 | ||
|
|
f6230e2f9d | ||
|
|
43e7917ec2 | ||
|
|
869d2bc2ec | ||
|
|
78ce91f1c2 | ||
|
|
4bad48d873 | ||
|
|
857a75baac | ||
|
|
992e930b86 | ||
|
|
47900f99c5 | ||
|
|
bdf13a63c4 | ||
|
|
d31e42699f | ||
|
|
d2739960af | ||
|
|
386359060b | ||
|
|
aa52ff6f4b | ||
|
|
eed99a588e | ||
|
|
02940796f1 | ||
|
|
bc411c24be | ||
|
|
76b56957e9 | ||
|
|
3c5c887a2c | ||
|
|
5d6b8a0ab6 | ||
|
|
8c4f96ef47 | ||
|
|
a7f967cf24 | ||
|
|
23e68cbdfb | ||
|
|
aa357d6d91 | ||
|
|
22df16186f | ||
|
|
5d0d243a45 | ||
|
|
1280e7e513 | ||
|
|
5c7755636d | ||
|
|
d20c7b09a6 | ||
|
|
139fd52477 | ||
|
|
72dd48a44c | ||
|
|
9200adea61 | ||
|
|
16e64d58ff | ||
|
|
8f9b2ab948 | ||
|
|
42086fdba7 | ||
|
|
8695ca8257 | ||
|
|
b443b5a89b | ||
|
|
79b3f4694d | ||
|
|
0e3e577568 | ||
|
|
5bb01ca9a3 | ||
|
|
86a0428d5f | ||
|
|
99a5ffae3b | ||
|
|
5a5bcb6b54 | ||
|
|
749ae11b15 | ||
|
|
007f0d214d | ||
|
|
e90782283c | ||
|
|
486111725e | ||
|
|
40717c931b | ||
|
|
142cf188a7 | ||
|
|
c70eefad50 | ||
|
|
74c23005c0 | ||
|
|
9c4dd7eb23 | ||
|
|
1ece9630e6 | ||
|
|
4524bbd8df | ||
|
|
d97db6ebaf | ||
|
|
25aa298c61 | ||
|
|
3a2074b633 | ||
|
|
ef05713d86 | ||
|
|
48cd33af18 | ||
|
|
80d3fd40f1 | ||
|
|
55185abec8 | ||
|
|
d0a8e3c60d | ||
|
|
0d44afed7e | ||
|
|
520f8e8042 | ||
|
|
19520d0008 | ||
|
|
23def04096 | ||
|
|
cc8835c7a3 | ||
|
|
3784a8e547 | ||
|
|
c6ab965062 | ||
|
|
667402846c | ||
|
|
f921cb943e | ||
|
|
a281455f0b | ||
|
|
73d85f6299 | ||
|
|
0473a3091c | ||
|
|
3ed9f4b7e4 | ||
|
|
00a9e95de9 | ||
|
|
0205f870db | ||
|
|
6442329717 | ||
|
|
f250c8cca5 | ||
|
|
2dfcc6463b | ||
|
|
d0e93fa34b | ||
|
|
401d72997b | ||
|
|
cde858d546 | ||
|
|
ba7c3dafab | ||
|
|
553262443a | ||
|
|
98a2322998 | ||
|
|
abbb1d7135 | ||
|
|
379f37307a | ||
|
|
ce48f43550 | ||
|
|
ea579ebfae | ||
|
|
c74bc2108c | ||
|
|
65168f77fb | ||
|
|
18225b9bd6 | ||
|
|
54c666a5ae | ||
|
|
275095a9c6 | ||
|
|
b6833b9f61 | ||
|
|
cc99d896be | ||
|
|
630e6becdf | ||
|
|
99be47a9a3 | ||
|
|
572d0c2340 | ||
|
|
19d975751f | ||
|
|
21b836a327 | ||
|
|
fe0325c6d1 | ||
|
|
e6537df806 | ||
|
|
7af6fa01f5 | ||
|
|
aee249b1dd | ||
|
|
81de82a1a4 | ||
|
|
d53584a10a | ||
|
|
a4bf6f83a6 | ||
|
|
50241b368b | ||
|
|
3ba1942631 | ||
|
|
642f6571ea | ||
|
|
446b284239 | ||
|
|
0154141304 | ||
|
|
fa56001f18 | ||
|
|
667f73aa54 | ||
|
|
f28c0fdfb0 | ||
|
|
0c99194b8c | ||
|
|
e36df2c8de | ||
|
|
461541348e | ||
|
|
45a411e8f8 | ||
|
|
60981e0801 | ||
|
|
012959e3cc | ||
|
|
46111dd091 | ||
|
|
39d1b2d395 | ||
|
|
06828b2e65 | ||
|
|
be85386e27 | ||
|
|
933aa480d3 | ||
|
|
f8f4a5c3b8 | ||
|
|
56685c6ec6 | ||
|
|
6bb4f4bf7d | ||
|
|
b58aa63796 | ||
|
|
e44899d510 | ||
|
|
860b3dd6b0 | ||
|
|
e44ff4666a | ||
|
|
bcd1f95e68 | ||
|
|
14e745950e | ||
|
|
6c4d880f2d | ||
|
|
524b84792f | ||
|
|
1635eadfcc | ||
|
|
5f4e39fea2 | ||
|
|
02c8532901 | ||
|
|
2944afa5b8 | ||
|
|
28a33cae8f | ||
|
|
49c9c9d4a1 | ||
|
|
e073f64be0 | ||
|
|
4c547008c5 | ||
|
|
592c3e2793 | ||
|
|
5d81363391 | ||
|
|
37e92e430b | ||
|
|
4cfc61147b | ||
|
|
6d6cbdf8c4 | ||
|
|
c106cf20cb | ||
|
|
b395190e42 | ||
|
|
b6a0f32b14 | ||
|
|
0407bbfbe6 | ||
|
|
6dff37594c | ||
|
|
7f9a03d6ab | ||
|
|
4f8465d8db | ||
|
|
3e85da9195 | ||
|
|
c8d58d2e7c | ||
|
|
8b1e3143a2 | ||
|
|
e32a0494d4 | ||
|
|
f850b7c894 | ||
|
|
9eb829aca3 | ||
|
|
71a024c789 | ||
|
|
f4b2ba1313 | ||
|
|
ed069bb9d4 | ||
|
|
da9a580a0d | ||
|
|
74ed67da7f | ||
|
|
b7f8bbb49f | ||
|
|
6b7aa124ed | ||
|
|
0281d10130 | ||
|
|
0b17cb621d | ||
|
|
db2a3174f6 | ||
|
|
47353e494d | ||
|
|
0f09630645 | ||
|
|
371f3d91ae | ||
|
|
8b478d0f15 | ||
|
|
15ec8e98db | ||
|
|
c2fe0c6818 | ||
|
|
b5442df02d | ||
|
|
81b94cebec | ||
|
|
c4b7a2e003 | ||
|
|
7af1b20686 | ||
|
|
2775135254 | ||
|
|
6d73515bf1 | ||
|
|
0344d578b2 | ||
|
|
2a3e162246 | ||
|
|
3984d12a30 | ||
|
|
ee0ec027db | ||
|
|
b1ff86832c | ||
|
|
e83e3ceadd | ||
|
|
bd2a84ccba | ||
|
|
6b8f4f7528 | ||
|
|
146dcf46f5 | ||
|
|
1d5357aaad | ||
|
|
861e17a3a7 | ||
|
|
5a311d8afe | ||
|
|
7695466081 | ||
|
|
c717c8a3ec | ||
|
|
37cbeff9f3 | ||
|
|
0d596fa8f7 | ||
|
|
42e1a17d6e | ||
|
|
3afec59523 | ||
|
|
bea6b98e84 | ||
|
|
46217c69bc | ||
|
|
3e87889bfb | ||
|
|
746a41937d | ||
|
|
93a384db77 | ||
|
|
7091be291c | ||
|
|
3571002422 | ||
|
|
86655eac66 | ||
|
|
536f5ce38b | ||
|
|
b6e6d7cd1a | ||
|
|
6714fb1d02 | ||
|
|
92a9591a41 | ||
|
|
2425493e10 | ||
|
|
c592ea6bac | ||
|
|
740f107ff9 | ||
|
|
f33b7bd617 | ||
|
|
4a90059fe2 | ||
|
|
aa521379dd | ||
|
|
5d3762456f | ||
|
|
1f9d1b5de1 | ||
|
|
02e2c9cd7f | ||
|
|
3f35eacad2 | ||
|
|
1ba178befb | ||
|
|
02a0e72f70 | ||
|
|
b4bc6cf3ee | ||
|
|
1684c73d4f | ||
|
|
b5c47f5255 | ||
|
|
7e8ec0e456 | ||
|
|
7436ac8e20 | ||
|
|
de00fdc17d | ||
|
|
75575f2006 | ||
|
|
db8556e724 | ||
|
|
e3a00bb5f9 | ||
|
|
af42f856ec | ||
|
|
809f3b7b5b | ||
|
|
9a21cd78ce | ||
|
|
be4498d394 | ||
|
|
5d3ae66e63 | ||
|
|
26573c3aa4 | ||
|
|
b2048d46d1 | ||
|
|
8ecbb74b00 | ||
|
|
9c81191b1d | ||
|
|
220414682e | ||
|
|
d11fca46fc | ||
|
|
5c8d5b2a8a | ||
|
|
87657c6297 | ||
|
|
af73951405 | ||
|
|
ab2119e9b8 | ||
|
|
6da3839b57 | ||
|
|
54ea293e7c | ||
|
|
25a0f3c3b8 | ||
|
|
6b55802df6 | ||
|
|
4b4babf1e7 | ||
|
|
26bc77ce56 | ||
|
|
7aee876d81 | ||
|
|
49c804b7ec | ||
|
|
295e7efddf | ||
|
|
9a426033ff | ||
|
|
6dc0f60faa | ||
|
|
44a4c1ba87 | ||
|
|
0d5c7b6d79 | ||
|
|
77c72b96aa | ||
|
|
510838bd70 | ||
|
|
49bb6c84b0 | ||
|
|
5fbea61e5a | ||
|
|
791f6328b0 | ||
|
|
e28c11f87d | ||
|
|
b9ca37b51f | ||
|
|
09416de0cd | ||
|
|
888b2afc0d | ||
|
|
106779208d | ||
|
|
7501911f17 | ||
|
|
a6b9312577 | ||
|
|
b43daa166f | ||
|
|
fd5cd1b058 | ||
|
|
304c978368 | ||
|
|
54f51f0d7d | ||
|
|
566a9a1551 | ||
|
|
957bcfa149 | ||
|
|
71dc6fe5bd | ||
|
|
5bda0a7dc3 | ||
|
|
6d977db1b5 | ||
|
|
7ec9b6e56e | ||
|
|
2127095e3b | ||
|
|
584937c761 | ||
|
|
306ed79932 | ||
|
|
5375ff0f9a | ||
|
|
9512a80804 | ||
|
|
3d472bde23 | ||
|
|
8761d4251f | ||
|
|
2846cc0570 | ||
|
|
30fef57f75 | ||
|
|
5d7d6ad9ab | ||
|
|
2589c0074d | ||
|
|
e780148305 | ||
|
|
edccb430c4 | ||
|
|
293832bafc | ||
|
|
e93e3b1e7d | ||
|
|
2c3dd946d5 | ||
|
|
4043e71f6c | ||
|
|
932fbb7d84 | ||
|
|
a4a548718d | ||
|
|
3a42a9e356 | ||
|
|
46cc5ce056 | ||
|
|
3b2d2863da | ||
|
|
aff5e23ecf | ||
|
|
2d91e2d578 | ||
|
|
690a63abd6 | ||
|
|
117ded88f0 | ||
|
|
bfba99827e | ||
|
|
44827a5020 | ||
|
|
055d1a9e1b | ||
|
|
ca4ca65c5e | ||
|
|
31dc035041 | ||
|
|
21f9af9d93 | ||
|
|
c7efd3a388 | ||
|
|
66aacc6fba | ||
|
|
79dea89f1f | ||
|
|
7d0efef62d | ||
|
|
933af60eba | ||
|
|
04fd41b288 | ||
|
|
002e1b68c6 | ||
|
|
73b756430f | ||
|
|
2452efa921 | ||
|
|
b6007e0a58 | ||
|
|
c9b4cae9dc | ||
|
|
86357bad54 | ||
|
|
1639189f26 | ||
|
|
c083fedaf4 | ||
|
|
c02945bc44 | ||
|
|
2edf3b23c1 | ||
|
|
c8ed328538 | ||
|
|
ef5ab1f1f2 | ||
|
|
14877a069b | ||
|
|
7aa1b51282 | ||
|
|
538017d1d2 | ||
|
|
b8c1b45316 | ||
|
|
407a718050 | ||
|
|
51be954c4b | ||
|
|
c537c52c96 | ||
|
|
6f96d7a3fa | ||
|
|
7590b50801 | ||
|
|
bd5d189a8f | ||
|
|
89268f4a45 | ||
|
|
3637205622 | ||
|
|
b4f9f0deac | ||
|
|
ec0e663cca | ||
|
|
26356dc34a | ||
|
|
b928963675 | ||
|
|
8451b961ad | ||
|
|
4a4bbab3c3 | ||
|
|
e5d2805b42 | ||
|
|
6f28b3633b | ||
|
|
c0eb612780 | ||
|
|
27dc9735e4 | ||
|
|
51e0df97e9 | ||
|
|
292fd532c9 | ||
|
|
aa7d960ef5 | ||
|
|
0b7213c890 | ||
|
|
63fe0eb5db | ||
|
|
ddce4bb446 | ||
|
|
dd3497e133 | ||
|
|
4f54379831 | ||
|
|
d77bc0e8a0 | ||
|
|
527ade245a | ||
|
|
dbcec4cf56 | ||
|
|
34fd7bdf7d | ||
|
|
81ab0ddc95 | ||
|
|
306ca984bc | ||
|
|
dd46a13dec | ||
|
|
ce5bc8cb01 | ||
|
|
b88bdfccd2 | ||
|
|
34aa22d0aa | ||
|
|
719d56ebfe | ||
|
|
87c8086fc1 | ||
|
|
eab4e47916 | ||
|
|
db87917daa | ||
|
|
183b4d4e7e | ||
|
|
00819258a7 | ||
|
|
c465ff5a81 | ||
|
|
1ac7ce3f3b | ||
|
|
55f5c8db69 | ||
|
|
5b0373db11 | ||
|
|
73be86c39e | ||
|
|
8dbe92a4a3 | ||
|
|
5a28a147f1 | ||
|
|
13a8640204 | ||
|
|
09b29436f4 | ||
|
|
421d527bfe | ||
|
|
24bd2b989a | ||
|
|
b2fad362f2 | ||
|
|
247c8f4eab | ||
|
|
adfde012ec | ||
|
|
57fd3ea5d8 | ||
|
|
d8948efb81 | ||
|
|
3966c92c71 | ||
|
|
1fbfbf74ef | ||
|
|
2604059961 | ||
|
|
6b44e35bec | ||
|
|
20bf7d957f | ||
|
|
c9f95eaf90 | ||
|
|
a2805bc934 | ||
|
|
b7529304f0 | ||
|
|
22c4b528d2 | ||
|
|
1158dc2a94 | ||
|
|
2765fc12bb | ||
|
|
18669641e9 | ||
|
|
cdd718ffb0 | ||
|
|
c5c5ff45aa | ||
|
|
5da3b7c393 | ||
|
|
2451e187be | ||
|
|
5e6529521c | ||
|
|
7cec547ecc | ||
|
|
c1a0561bf3 | ||
|
|
fafc1881b5 | ||
|
|
a59abe932e | ||
|
|
452e3ccad1 | ||
|
|
8413ec08f7 | ||
|
|
603a7d022c | ||
|
|
b2dc45006d | ||
|
|
1828cf87a0 | ||
|
|
a73eac190b | ||
|
|
0e5c511c01 | ||
|
|
2e6b38cef0 | ||
|
|
d7ca93cc2c | ||
|
|
82e4e032df | ||
|
|
ca2ca16146 | ||
|
|
14c4c2a1d7 | ||
|
|
4842f23765 | ||
|
|
7721d59e1a | ||
|
|
76dbc32f39 | ||
|
|
f23066f0da | ||
|
|
cbbd317fb5 | ||
|
|
d54c4345d3 | ||
|
|
bdf0be87c6 | ||
|
|
0155b89953 |
No files matched your search
@@ -2,7 +2,7 @@
|
||||
name: reverse-engineer-anything
|
||||
description: Reverse engineer native, managed, Electron/JavaScript, packaged, firmware, and browser targets with REA. Use shipped-artifact or requested runtime evidence to explain features, compare versions, decompile code, or guide a reconstruction. Skip REA for ordinary source-repository architecture analysis.
|
||||
metadata:
|
||||
version: "44"
|
||||
version: "45"
|
||||
---
|
||||
|
||||
# REA
|
||||
@@ -32,6 +32,15 @@ original task after repair. Client approval, shell PATH, registration and engine
|
||||
availability have different remedies; avoid repeating setup for all of them.
|
||||
If the host times out without a REA result, do not repeat the unchanged call or
|
||||
assume work stopped. Read the recovery guide's deadline distinction before retrying.
|
||||
If the MCP connection drops, retry that call once only when it is safe to
|
||||
repeat or known not to have started. If it may already have changed the
|
||||
target, or it fails again, tell the user and ask them to restart the MCP
|
||||
client. If REA could not start its connection, retry once, then tell the user
|
||||
and ask them to restart the MCP client. Do not retry a startup failure that
|
||||
returns the same unchanged result. Run `rea doctor` when REA could not start
|
||||
or tools stay missing after that restart. For `cleanup_incomplete`, a retryable
|
||||
capacity limit, or `configuration_invalid`, follow the recovery guide's ladder
|
||||
before asking for a restart. Read that guide before a second repair attempt.
|
||||
|
||||
1. Diagnose without changing REA or client configuration. `npx` may download
|
||||
the package and write to npm's cache. For Codex, run
|
||||
@@ -126,7 +135,10 @@ explicit path or endpoint and do not need it.
|
||||
connect Everywhere's separate MCP server for live traffic.
|
||||
- Retained HAR/SAZ/native mitmproxy/aioquic qlog capture: `inspect_web_network_capture`. Select
|
||||
original record ordinals when useful; inspect producer fields and byte/number
|
||||
sidecars without fetching recorded URLs or claiming live attribution. See
|
||||
sidecars without fetching recorded URLs or claiming live attribution. HAR/SAZ/qlog
|
||||
old-generation heap is `REA_CAPTURE_DECODER_OLD_GENERATION_MIB` (default 192 MiB,
|
||||
floor 8, maximum 16384), set where REA starts. Host memory and `NODE_OPTIONS` do not
|
||||
raise it. See
|
||||
[historical captures](https://github.com/morluto/rea/blob/main/docs/web-network-captures.md) for the exact upstream
|
||||
profile and credential exclusions. Qlog support starts with aioquic 1.5.0
|
||||
JSON 0.3; stream coverage and endpoint loss declarations do not recover bodies
|
||||
@@ -166,6 +178,14 @@ explicit path or endpoint and do not need it.
|
||||
Select JavaScript glue and candidate paths explicitly and preserve URL/path
|
||||
ambiguity. No implicit fetch or target execution; WAT is not original source.
|
||||
See the [WASM guide](https://github.com/morluto/rea/blob/main/docs/wasm-artifacts.md).
|
||||
- Explicit local Android APK (or ZIP/AAB) signing: `inspect_apk_signature`.
|
||||
Prefer its summary or selected signer/digest/lineage page; retain complete
|
||||
Evidence and use `inspect_analysis_view` kind `apk-signature` for follow-ups.
|
||||
Reports which schemes are present (v1 JAR, v2, v3, v3.1), each signer's
|
||||
certificate SHA-256 fingerprint (v1 included, from its PKCS#7 block), v3 key-rotation lineage, source stamp, and
|
||||
whether each signed digest still matches the bytes (self-consistency). This
|
||||
is identity and integrity, not a trust or authenticity verdict.
|
||||
See the [APK signature guide](https://github.com/morluto/rea/blob/main/docs/apk-signature.md).
|
||||
- Explicit local EVM bytecode carrier: `inspect_evm_interface` with caller-selected
|
||||
`raw` or `hex` encoding. The owned worker deadline is `timeout_ms` (default
|
||||
30000 ms, range 1..2147483647, next call). It does not raise the fixed byte,
|
||||
@@ -219,6 +239,33 @@ explicit path or endpoint and do not need it.
|
||||
delivery requires `--evidence_output`.
|
||||
See the
|
||||
[Rust binary guide](https://github.com/morluto/rea/blob/main/docs/rust-binaries.md).
|
||||
- PE Authenticode certificate table: `inspect_pe_certificates` with the explicit
|
||||
local PE32/PE32+ file. This built-in target-free inspection requires no
|
||||
Windows SDK. Preserve WIN_CERTIFICATE ranges, types, payload SHA-256, and
|
||||
PKCS#7 signer/X.509 identity fields, including `subject_key_identifier_hex`
|
||||
when the signer uses that form. A missing security directory is observed
|
||||
absence of that table, not proof the image is unsigned in every catalog sense.
|
||||
Signatures are not verified. See the
|
||||
[PE certificate guide](https://github.com/morluto/rea/blob/main/docs/pe-certificates.md).
|
||||
- ELF note tables: `inspect_elf_notes` with the explicit local ELF32/ELF64
|
||||
file. This built-in target-free inspection requires no disassembler. Preserve
|
||||
PT_NOTE and SHT_NOTE ranges, owners, types, descriptor SHA-256, and GNU
|
||||
build-id or ABI-tag fields. A missing table is observed absence of those
|
||||
declarations, not proof the image never carried notes. See the
|
||||
[ELF notes guide](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
|
||||
- CPython 3.7–3.13 `.pyc` header, nested marshal code objects and bytecode
|
||||
identity: `inspect_python_pyc` with the explicit local file. This built-in
|
||||
target-free inspection requires no Python installation. Preserve magic,
|
||||
PEP 552 hash or mtime/size, nested names, and bytecode SHA-256. Bytecode is
|
||||
not decompiled, and a decoded header does not prove the matching `.py` is
|
||||
present. See the
|
||||
[CPython pyc guide](https://github.com/morluto/rea/blob/main/docs/python-pyc.md).
|
||||
- Erlang BEAM IFF container: `inspect_erlang_beam` with the explicit local
|
||||
`.beam` file. This built-in target-free inspection requires no Erlang
|
||||
installation. Preserve chunk names, atom order, export/import/lambda tables,
|
||||
and the Code header. Missing optional tables stay null. Bytecode is not
|
||||
executed. See the
|
||||
[Erlang BEAM guide](https://github.com/morluto/rea/blob/main/docs/erlang-beam.md).
|
||||
|
||||
- Explicit local SQLite database snapshot: `inspect_sqlite_database`. Inspect
|
||||
with Node.js 24.x >=24.15 or 26+ providing native SQLite limits. Read schema
|
||||
@@ -241,6 +288,8 @@ explicit path or endpoint and do not need it.
|
||||
- PE resource type/name/language trees and static icon group references:
|
||||
`inspect_pe_resources` with an explicit path. This portable operation requires
|
||||
no active target or engine; opaque payloads retain file ranges and SHA-256.
|
||||
- PE export directories and ELF dynamic-symbol exports: `inspect_native_exports`
|
||||
with an explicit path; portable, no active target or engine.
|
||||
- Native executable, library, or analysis database: `open_binary`, then
|
||||
use focused analysis tools directly; call `binary_overview` when metadata or
|
||||
inventory context is useful and available from the selected provider.
|
||||
|
||||
@@ -11,14 +11,15 @@ main and an older release expose the same arguments.
|
||||
|
||||
## Choose the remedy from the observed failure
|
||||
|
||||
| Observation | Meaning and next step |
|
||||
| --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| No REA tools in the active session | Inspect registration with `rea doctor --client codex --json`. A skill installation alone does not register MCP. |
|
||||
| Missing, malformed or stale registration | Prepare a scoped setup plan; apply only authorized changes with backups. |
|
||||
| Aligned registration, but no connected tools | Restart/reconnect the client. Doctor checks registration; it cannot establish the current agent's connection. Inspect the client's launch error if reconnection fails. |
|
||||
| `MCP tool call requires approval, but approval policy is never` | Codex rejected the call before REA executed it. Do not install an engine or repeat setup to solve this client-policy decision. See the approval section below. |
|
||||
| REA returns `provider_unavailable` or an unavailable tool entry | Read that operation's provider diagnostics or `binary_session.result.tool_availability`. Expand each group's tool names and inherit the shared client requirements unless overridden. Use the operation's availability, reason, and remediation; a complete tool catalog does not imply every operation is available. |
|
||||
| `rea` is missing in a child shell, or Node is incompatible | Inspect the actual shell PATH and launcher/runtime. A prefix installation may be absent from a login shell's PATH; this does not establish a broken MCP registration. |
|
||||
| Observation | Meaning and next step |
|
||||
| --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| No REA tools in the active session | Inspect registration with `rea doctor --client codex --json`. A skill installation alone does not register MCP. |
|
||||
| Missing, malformed or stale registration | Prepare a scoped setup plan; apply only authorized changes with backups. |
|
||||
| Aligned registration, but no connected tools | Restart/reconnect the client. Doctor checks registration; it cannot establish the current agent's connection. Inspect the client's launch error if reconnection fails. |
|
||||
| MCP connection dropped or REA could not start | If the connection drops, retry that call once only when it is safe to repeat or known not to have started. If it may already have changed the target, or the same failure returns, tell the user REA's connection failed and ask them to restart the MCP client. If REA could not start its connection, retry once, then tell the user and ask them to restart the MCP client. Do not retry a startup failure that returns the same unchanged result. Run `rea doctor` when REA could not start or tools stay missing after restart. Doctor cannot restore a live connection by itself. |
|
||||
| `MCP tool call requires approval, but approval policy is never` | Codex rejected the call before REA executed it. Do not install an engine or repeat setup to solve this client-policy decision. See the approval section below. |
|
||||
| REA returns `provider_unavailable` or an unavailable tool entry | Read that operation's provider diagnostics or `binary_session.result.tool_availability`. Expand each group's tool names and inherit the shared client requirements unless overridden. Use the operation's availability, reason, and remediation; a complete tool catalog does not imply every operation is available. |
|
||||
| `rea` is missing in a child shell, or Node is incompatible | Inspect the actual shell PATH and launcher/runtime. A prefix installation may be absent from a login shell's PATH; this does not establish a broken MCP registration. |
|
||||
|
||||
If the client cannot launch its shell/sandbox helper or read the installed skill,
|
||||
inspect its launch diagnostic. For example, Codex can refuse helper aliases when
|
||||
@@ -56,8 +57,13 @@ authorized CLI fallback. Do not silently broaden permissions or switch targets.
|
||||
|
||||
A returned REA `provider_timeout` instead means the **server/provider** reached
|
||||
its deadline. Follow its `remediation.action`, reuse accessible partial Evidence,
|
||||
and resolve reported incomplete cleanup before retrying. Raising only the
|
||||
client deadline does not change this server budget. For static JavaScript,
|
||||
and resolve reported incomplete cleanup before retrying. Change a request
|
||||
field or a `REA_*` setting only when the returned remediation explicitly
|
||||
recommends that change. Restart REA when that text says the value is read at
|
||||
startup. A mention that a control does not raise the deadline is not a
|
||||
recommendation to change it. Do not invent a setting the remediation does not
|
||||
name. Raising only the client deadline does not change
|
||||
this server budget. For static JavaScript,
|
||||
`analysis_timeout_ms` (CLI `rea analyze-javascript-application <path>
|
||||
--analysis-timeout-ms <milliseconds>`) controls each source's
|
||||
startup, analysis and transfer deadline in **milliseconds**. Increase that
|
||||
@@ -75,6 +81,37 @@ installed CLI's command help. Refresh the catalog if stale; do not guess fields
|
||||
from an older skill or return the entire catalog to repair one field. Correct
|
||||
all reported fields before retrying.
|
||||
|
||||
## Recovery ladder
|
||||
|
||||
Follow the returned remediation. Change a request field or a `REA_*` setting
|
||||
only when that text explicitly recommends the change. Restart REA when it says
|
||||
the value is read at startup. A mention that a control does not raise a limit
|
||||
is not a recommendation to change it. Do not invent a setting. Host memory and
|
||||
`NODE_OPTIONS` do not raise a REA admission unless that remediation says so.
|
||||
|
||||
- MCP connection dropped: retry that call once only when it is safe to repeat
|
||||
or known not to have started. If it may already have changed the target, or
|
||||
it fails again, tell the user REA's connection failed and ask them to restart
|
||||
the MCP client. Do not run `rea doctor` for the drop itself.
|
||||
- REA could not start its connection: retry once, then tell the user and ask
|
||||
them to restart the MCP client. Run `rea doctor` when REA could not start or
|
||||
tools stay missing after that restart. Do not retry a startup failure that
|
||||
returns the same unchanged result.
|
||||
- `cleanup_incomplete`, or retained cleanup owners in the error details: retry
|
||||
that exact cleanup owner. Do not start new work that needs those resources
|
||||
until that owner confirms release. Repeating the original call is not that
|
||||
retry.
|
||||
- Capacity, when the result is `resource_constraint` and `retryable` is true:
|
||||
wait for the active admission to finish, then retry within the reported
|
||||
limits. Do not restart REA to free the slot.
|
||||
- `configuration_invalid`: correct the named setting in the environment that
|
||||
starts REA (the shell or the MCP registration), then restart REA. Run
|
||||
`rea doctor` to see the `runtime-configuration:` check. Re-run `rea setup`
|
||||
for that client when the registration must carry the new setting, then
|
||||
reconnect.
|
||||
- `invalid_request`: correct the reported fields from the current schema. Do
|
||||
not repeat the unchanged call.
|
||||
|
||||
## Repair registration when needed
|
||||
|
||||
For Codex:
|
||||
|
||||
@@ -93,10 +93,14 @@ Use `view: {kind: "environment-state"}` with the manifest's `template_rules` to
|
||||
extract the data those reads observed instead: entity types and identity
|
||||
fields, entities with recorded values, documents, and per-tool render plans
|
||||
checked against the recordings. The state comes only from reads before the
|
||||
first related write; types, identity and list membership are inferences.
|
||||
first related write; types, identity and list membership are inferences. The
|
||||
view also gives each state-changing tool a write plan, served only when a later
|
||||
recorded read confirms its effect and none contradicts it.
|
||||
`rea environment-serve manifest.json --evidence capture.json` derives that
|
||||
state at startup, answers read tools from it and serves `data/reset`,
|
||||
`data/add` and `data/get` on `/agentenv`; write tools are not served. It
|
||||
replays the capture instead with `--replay-only` or when the state is
|
||||
unavailable (not derivable, or a catalog over the discovery budget), and its
|
||||
stopped document's `state` says which applied.
|
||||
state at startup, answers read tools from it, serves the write tools whose plan
|
||||
is served, each applying its effect to that state, and serves `data/reset`,
|
||||
`data/add` and `data/get` on `/agentenv`; other write tools are not served, and
|
||||
each plan states why in its `reason`. It replays the capture instead with
|
||||
`--replay-only` or when the state is unavailable (not derivable, or a catalog
|
||||
over the discovery budget), and its stopped document's `state` says which
|
||||
applied.
|
||||
@@ -22,6 +22,11 @@ requires complete application analysis; `source_paths: []` is invalid, not an
|
||||
unfiltered request. `detail: "summary"` reduces delivery
|
||||
and does not by itself reduce analysis work.
|
||||
|
||||
ASAR header/index admission defaults to 16 MiB / 16777216 bytes;
|
||||
`REA_ASAR_MAX_HEADER_BYTES` (at most 256 MiB, set where REA starts) changes it.
|
||||
`source_paths`, `detail`, and `max_heap_mb` do not bypass or raise it. Or
|
||||
analyze an extracted directory.
|
||||
|
||||
Exact `#alias` specifiers resolve through the importer's
|
||||
enclosing package `imports` map to package-local files; nested `node_modules`
|
||||
packages use their own map. Wildcard, recursive, and external-package import
|
||||
@@ -54,6 +59,20 @@ in the same session. A returned `error.details.partial_observation` reference
|
||||
can be supplied directly to `inspect_analysis_view`. If the SDK cancels locally, retrieve its recorded ID from
|
||||
the Evidence bundle before inspecting the partial analysis.
|
||||
|
||||
## Inventory route candidates without returning the application graph
|
||||
|
||||
When the advertised schema supports `view`, use `detail: "summary"` with
|
||||
`view: {kind: "javascript-routes", collection: "routes", fields: ["path", "confidence"], limit: 20}`.
|
||||
The same view works with `analyze_web_bundle` on already selected captured sources.
|
||||
The complete source Evidence is retained; use its `parent_evidence_id` with
|
||||
`inspect_analysis_view` for `summary`, `routes`, `occurrences`, `sources`, or
|
||||
`unknowns`. Filter and batch IDs before requesting more fields, and follow
|
||||
`coverage.next_offset`. CLI selections require `--evidence_output` to keep the
|
||||
complete record. Static patterns, inferred deployment bases, heuristic system
|
||||
classification, and unavailable sources never establish route reachability or
|
||||
the complete application route denominator. See the
|
||||
[route inventory guide](https://github.com/morluto/rea/blob/main/docs/javascript-route-inventory.md).
|
||||
|
||||
## Read a module without repeating analysis
|
||||
|
||||
Use the actual returned parent ID, on the same connection, as `source.evidence_id`.
|
||||
|
||||
@@ -45,7 +45,8 @@ See [desktop installations](https://github.com/morluto/rea/blob/main/docs/deskto
|
||||
|
||||
## Go build metadata
|
||||
|
||||
Use `inspect_go_binary` for an explicit local ELF, PE or thin Mach-O when the
|
||||
Use `inspect_go_binary` for an explicit local ELF, PE or Mach-O (universal
|
||||
files need `architecture`) when the
|
||||
question concerns the embedded compiler version, module/dependency versions,
|
||||
local replacements or build settings. No `open_binary`, Go installation or
|
||||
target execution is required. The CLI equivalent is `inspect-go-binary PATH`.
|
||||
@@ -84,7 +85,8 @@ See [IL2CPP metadata](https://github.com/morluto/rea/blob/main/docs/il2cpp-metad
|
||||
|
||||
## Rust dependency metadata
|
||||
|
||||
Use `inspect_rust_binary` for an explicit local ELF, PE, or thin Mach-O when
|
||||
Use `inspect_rust_binary` for an explicit local ELF, PE, or Mach-O (universal
|
||||
files need `architecture`) when
|
||||
the question concerns the cargo-auditable crate list embedded in `.dep-v0`
|
||||
(Mach-O: `__DATA,.dep-v0`). No `open_binary`, Rust installation, or target
|
||||
execution is required. The CLI equivalent is `inspect-rust-binary PATH`.
|
||||
@@ -94,6 +96,51 @@ dependencies. An omitted package kind stays null. A rustc commit hash is
|
||||
inferred from a read-only `/rustc/<40-hex>/` path and does not by itself
|
||||
identify the compiler. See [Rust binaries](https://github.com/morluto/rea/blob/main/docs/rust-binaries.md).
|
||||
|
||||
## PE Authenticode certificate tables
|
||||
|
||||
Use `inspect_pe_certificates` for an explicit local PE32/PE32+ image when the
|
||||
question concerns the Authenticode certificate table, WIN_CERTIFICATE types, or
|
||||
embedded PKCS#7 signer and X.509 identity fields. No `open_binary`, Windows SDK,
|
||||
or target execution is required. The CLI equivalent is
|
||||
`inspect-pe-certificates PATH`. Preserve artifact SHA-256, table file ranges,
|
||||
payload hashes, original validity-time spellings, and
|
||||
`subject_key_identifier_hex` when the signer uses that form. A missing
|
||||
`IMAGE_DIRECTORY_ENTRY_SECURITY` directory is observed absence of that table,
|
||||
not proof the image is unsigned in every catalog or overlay sense. Signatures,
|
||||
chains, timestamps, and Authenticode digest coverage remain unobserved. See
|
||||
[PE Authenticode certificate tables](https://github.com/morluto/rea/blob/main/docs/pe-certificates.md).
|
||||
|
||||
## ELF note tables
|
||||
|
||||
Use `inspect_elf_notes` for an explicit local ELF32/ELF64 image when the
|
||||
question concerns PT_NOTE/SHT_NOTE owners, GNU build-id, or GNU ABI-tag
|
||||
fields. No `open_binary` or target execution is required. The CLI equivalent
|
||||
is `inspect-elf-notes PATH`. Preserve artifact SHA-256, table file ranges,
|
||||
descriptor hashes, and original owner spellings. A missing table is observed
|
||||
absence of those declarations, not proof the image never carried notes in
|
||||
another container. See
|
||||
[ELF note tables](https://github.com/morluto/rea/blob/main/docs/elf-notes.md).
|
||||
|
||||
## CPython pyc files
|
||||
|
||||
Use `inspect_python_pyc` for an explicit local CPython 3.7–3.13 `.pyc` when the
|
||||
question concerns the header magic, PEP 552 source hash or timestamp, nested
|
||||
code-object names, or bytecode identity. No `open_binary`, Python installation,
|
||||
or target execution is required. The CLI equivalent is `inspect-python-pyc PATH`.
|
||||
Preserve artifact SHA-256, the 16-byte header fields, nested code names, and
|
||||
bytecode SHA-256. Bytecode is not decompiled. A decoded header does not prove
|
||||
the matching `.py` is present. See [CPython pyc inspection](https://github.com/morluto/rea/blob/main/docs/python-pyc.md).
|
||||
|
||||
## Erlang BEAM files
|
||||
|
||||
Use `inspect_erlang_beam` for an explicit local `FOR1`/`BEAM` file when the
|
||||
question concerns IFF chunks, atom names, exports, imports, lambdas, or the
|
||||
Code header. No `open_binary`, Erlang installation, or bytecode execution is
|
||||
required. The CLI equivalent is `inspect-erlang-beam PATH`. Preserve artifact
|
||||
SHA-256, chunk file ranges, 1-based atom indices, and original atom spellings.
|
||||
Missing optional tables stay null. See
|
||||
[Erlang BEAM files](https://github.com/morluto/rea/blob/main/docs/erlang-beam.md).
|
||||
|
||||
## SQLite snapshots
|
||||
|
||||
Use `inspect_sqlite_database` with an explicit local database snapshot for its
|
||||
@@ -148,6 +195,30 @@ and tool profile. Text offsets count UTF-16 code units; follow `next_offset`.
|
||||
The complete source remains retained after an oversized MCP reply. No target
|
||||
execution or network acquisition is implied, and WAT is decoded representation.
|
||||
|
||||
## Offline APK signatures
|
||||
|
||||
Use `inspect_apk_signature` for a selected local APK/ZIP/AAB. Default MCP summaries
|
||||
retain complete Evidence. Select `view.collection: signers/digests/lineage`,
|
||||
with scheme or ID batches, fields and paging; use `inspect_analysis_view` kind
|
||||
`apk-signature` for retained reads after deletion. IDs retain artifact/scheme
|
||||
scope and signer links; `fields: []` keeps identity links. Empty pages preserve
|
||||
partial decoding reasons and unknown authenticity. CLI compact delivery needs
|
||||
`--evidence_output` to preserve the complete parent.
|
||||
It reads the APK
|
||||
Signing Block (v2/v3/v3.1) and v1 `META-INF` signing without executing anything,
|
||||
and reports each signer's certificate facts (for v1, the certificate the PKCS#7
|
||||
block's SignerInfo names), the declared v3 rotation lineage,
|
||||
the declared source-stamp certificate and, for SHA-256/SHA-512 digests, whether
|
||||
the declared content digest matches the current bytes. That match is not a
|
||||
signature verification: anyone who changes the bytes can recompute the digest.
|
||||
`posture` summarises v1-only signing (which cannot tell a v1-only APK from one
|
||||
whose v2/v3 block was removed), observed signer agreement across schemes,
|
||||
whether the v1 signer equals the block-scheme signer (`false` is notable),
|
||||
whether every differing signer appears in a declared (unverified) rotation
|
||||
lineage, and the strongest scheme.
|
||||
It never claims authenticity: no signature or lineage is cryptographically
|
||||
verified.
|
||||
|
||||
## Native targets
|
||||
|
||||
After `open_binary`, use focused search, procedure, or function tools directly.
|
||||
@@ -225,6 +296,35 @@ Exported C and embedded resources remain useful independent evidence, but a
|
||||
timeout does not establish complete analysis or absence of code. See the
|
||||
[deadline and client guide](https://github.com/morluto/rea/blob/main/docs/mcp-contracts.md#ghidra-first-query-deadlines-and-recovery).
|
||||
|
||||
## Bridge request ceiling
|
||||
|
||||
Hopper and Cutter share `REA_BRIDGE_MAX_REQUEST_BYTES`. Unset, both sides use
|
||||
16777216 bytes. The payload budget excludes the terminating LF. A decimal
|
||||
integer from 7464 to 536870887 raises or lowers that ceiling. The floor fits
|
||||
the largest bounded symbol-name command. A tight Cutter status still returns
|
||||
its session id and up to 64 completion receipts. Its path is included when it
|
||||
fits, and is unknown when it does not, so an older descriptor path is not
|
||||
paired with the new generation. The maximum is the encoded payload, one byte under Node's string ceiling so
|
||||
the framing LF still fits. Cutter measures, signs, and writes a fitting
|
||||
response in bounded chunks. The bridge searches only the newly read bytes
|
||||
for the framing LF. The client unescapes each socket chunk into one response
|
||||
string before parsing it, so this ceiling does not keep the paged wire frame
|
||||
and another concatenated copy. Invalid values are configuration errors and do not fall back to 16777216. Set the variable in the environment that starts REA, restart REA,
|
||||
and start Hopper or Cutter from that same environment. An out-of-band bridge
|
||||
without the setting stays at 16777216 bytes. The client reports that mismatch
|
||||
during discovery only after the hello proves a live authenticated bridge, and
|
||||
does not send a status request or the command. A stale descriptor is ignored.
|
||||
Discovery fails if any such live ceiling differs, even when another live
|
||||
session matches. A command response discarded for that ceiling stays an
|
||||
unknown execution with `output_truncated`. A hello
|
||||
that never sends its authenticated frame does not hold the accept loop.
|
||||
At most 8 connection threads run; a further accept is closed, and a failure
|
||||
to start a thread does not stop the listener. `completed_connection` is the
|
||||
longest prefix of connections that have terminated. Dense scalar replies are
|
||||
encoded in bounded batches.
|
||||
The 25000 ms Cutter request deadline and the 256-candidate discovery budget
|
||||
still have no runtime override.
|
||||
|
||||
## Static memory and original file bytes
|
||||
|
||||
For Ghidra, `read_bytes` reads initialized analysis memory, including loader
|
||||
@@ -366,6 +466,8 @@ For headerless DOS COM, explicitly open with `format: "dos-com"` (CLI
|
||||
analysis: the entry is `0x10100`, file offset zero, with imposed real-mode segment
|
||||
context. PSP/stack/device state remains unmodeled. See [DOS guide](https://github.com/morluto/rea/blob/main/docs/ghidra-dos.md).
|
||||
|
||||
Use `inspect_byte_entropy` to triage high- and low-entropy ranges before extraction.
|
||||
|
||||
For other headerless images (embedded firmware without ELF/Mach-O/PE/MZ
|
||||
headers), open with `format: "raw-binary"`, `architecture` (`x86`, `x86_64`,
|
||||
`arm`, `arm64`, `6502`, or `m68k`), and `entry_point` (`0x` hex). File offset 0 is mapped at
|
||||
@@ -394,6 +496,16 @@ Other payloads are opaque, and this operation does not decode images or simulate
|
||||
Windows resource loading. Consult the budgets and supported tree profile in
|
||||
[offline binary diagnostics](https://github.com/morluto/rea/blob/main/docs/binary-diagnostics.md).
|
||||
|
||||
## Offline PE and ELF export tables
|
||||
|
||||
Use `inspect_native_exports` with an absolute `path`, or
|
||||
`rea inspect-native-exports ./libexample.so --json`, to read a PE export
|
||||
directory or ELF dynamic symbol table on any host without opening a native
|
||||
target. Ordinal-only, forwarded and hidden-version exports stay distinct;
|
||||
partial or unsupported coverage means the inventory is incomplete, not that
|
||||
exports are absent. Use `inspect_macho` for Mach-O. See
|
||||
[offline binary diagnostics](https://github.com/morluto/rea/blob/main/docs/binary-diagnostics.md).
|
||||
|
||||
For exact core-module import/export differences, use `compare_wasm_interfaces`
|
||||
with two complete inspection Evidence records (or current-session retained
|
||||
references) and explicit scope. Preserve unknown types/duplicate names; static
|
||||
|
||||
@@ -17,7 +17,10 @@ describe the use case and observable outcome. -->
|
||||
## Change and scope
|
||||
|
||||
<!-- Explain the chosen approach, why it fits REA's architecture, and what is
|
||||
intentionally not included. -->
|
||||
intentionally not included. If adding complexity for a speculative or vanishingly
|
||||
unlikely race or security edge case, record the concrete failure mode, likelihood,
|
||||
complexity cost, and the user's buy-in obtained before implementation. Do not
|
||||
silently expand scope for theoretical robustness. -->
|
||||
|
||||
Follow the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope).
|
||||
Unresolved scope, authority, side effects, or required verification block
|
||||
|
||||
@@ -72,6 +72,7 @@ jobs:
|
||||
browser: ${{ steps.plan.outputs.browser }}
|
||||
binary_layout: ${{ steps.plan.outputs.binary_layout }}
|
||||
evm: ${{ steps.plan.outputs.evm }}
|
||||
apk_signature: ${{ steps.plan.outputs.apk_signature }}
|
||||
javascript_recovery: ${{ steps.plan.outputs.javascript_recovery }}
|
||||
recorded_crash: ${{ steps.plan.outputs.recorded_crash }}
|
||||
web_network: ${{ steps.plan.outputs.web_network }}
|
||||
@@ -384,6 +385,7 @@ jobs:
|
||||
needs.changes.outputs.browser == 'true' ||
|
||||
needs.changes.outputs.binary_layout == 'true' ||
|
||||
needs.changes.outputs.evm == 'true' ||
|
||||
needs.changes.outputs.apk_signature == 'true' ||
|
||||
needs.changes.outputs.javascript_recovery == 'true' ||
|
||||
needs.changes.outputs.recorded_crash == 'true' ||
|
||||
needs.changes.outputs.web_network == 'true' ||
|
||||
@@ -762,6 +764,7 @@ jobs:
|
||||
tests/boundary/mcp/nativeDemangleMcp.test.ts
|
||||
tests/boundary/providers/native/nativeSignatureTargetBinding.test.ts
|
||||
tests/boundary/cli/nativeSignatureCli.test.ts
|
||||
tests/boundary/cli/nativeMachoArm64_32Cli.test.ts
|
||||
tests/boundary/mcp/nativeSignatureTargetBindingMcp.test.ts
|
||||
src/process/capture/FilesystemSnapshot.test.ts
|
||||
tests/process-global/filesystemSnapshotFallbackCancellation.test.ts
|
||||
@@ -930,7 +933,7 @@ jobs:
|
||||
tests/boundary/filesystem/javascriptArtifactContentIdentity.test.ts
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: 22.19.0
|
||||
node-version: 22.23.4
|
||||
- name: Verify native path boundaries on Node 22
|
||||
run: >-
|
||||
npx vitest run --coverage.enabled=false
|
||||
@@ -1003,6 +1006,16 @@ jobs:
|
||||
build_cache_artifact: rea-build-cache
|
||||
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
||||
|
||||
apk_signature:
|
||||
needs: [changes, static, build]
|
||||
if: needs.changes.outputs.apk_signature == 'true'
|
||||
secrets:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
uses: ./.github/workflows/real-apk-signature.yml
|
||||
with:
|
||||
build_cache_artifact: rea-build-cache
|
||||
remote_cache_write: ${{ inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) }}
|
||||
|
||||
javascript_recovery:
|
||||
needs: [changes, static, build]
|
||||
if: needs.changes.outputs.javascript_recovery == 'true'
|
||||
@@ -1103,6 +1116,7 @@ jobs:
|
||||
browser,
|
||||
binary_layout,
|
||||
evm,
|
||||
apk_signature,
|
||||
javascript_recovery,
|
||||
recorded_crash,
|
||||
web_network,
|
||||
|
||||
@@ -25,16 +25,16 @@ jobs:
|
||||
node-version-file: .nvmrc
|
||||
- name: Validate the SDK pin against the provider's verified release
|
||||
run: node scripts/verify-ghidra-bridge-sources.mjs --check-sdk-pin >> "$GITHUB_ENV"
|
||||
# Only the jars and application.properties are extracted: the check
|
||||
# compiles against them and never launches Ghidra or imports a target.
|
||||
- name: Acquire checksum-verified Ghidra jars in isolated runner storage
|
||||
# The bridge probe imports only source-owned ARM/Thumb bytes and never
|
||||
# executes target code. All SDK/project state stays in runner storage.
|
||||
- name: Acquire checksum-verified Ghidra SDK in isolated runner storage
|
||||
shell: bash
|
||||
run: |
|
||||
ghidra_root="${RUNNER_TEMP}/rea-ghidra"
|
||||
mkdir -p "${ghidra_root}"
|
||||
curl -fsSL --retry 3 --write-out 'ghidra_download_bytes=%{size_download} ghidra_download_seconds=%{time_total}\n' -o "${ghidra_root}/ghidra.zip" "${GHIDRA_RELEASE_URL}"
|
||||
echo "${GHIDRA_RELEASE_SHA256} ${ghidra_root}/ghidra.zip" | sha256sum -c -
|
||||
unzip -q "${ghidra_root}/ghidra.zip" '*/Ghidra/*.jar' '*/Ghidra/application.properties' -d "${ghidra_root}"
|
||||
unzip -q "${ghidra_root}/ghidra.zip" -d "${ghidra_root}"
|
||||
rm "${ghidra_root}/ghidra.zip"
|
||||
properties="$(find "${ghidra_root}" -path '*/Ghidra/application.properties' -print -quit)"
|
||||
test -n "${properties}"
|
||||
@@ -46,3 +46,19 @@ jobs:
|
||||
java_home_variable="JAVA_HOME_${GHIDRA_JAVA_MAJOR}_X64"
|
||||
test -n "${!java_home_variable}"
|
||||
JAVA_HOME="${!java_home_variable}" npm run verify:ghidra:bridge-sources -- --verified-sdk
|
||||
- name: Inspect real ARM and Thumb instruction context through the bridge
|
||||
shell: bash
|
||||
run: |
|
||||
java_home_variable="JAVA_HOME_${GHIDRA_JAVA_MAJOR}_X64"
|
||||
export JAVA_HOME="${!java_home_variable}"
|
||||
probe_root="${RUNNER_TEMP}/rea-arm-context"
|
||||
mkdir -p "${probe_root}/project"
|
||||
printf '\036\377\057\341\160\107\000\000' > "${probe_root}/arm-thumb.bin"
|
||||
timeout 180s "${GHIDRA_INSTALL_DIR}/support/analyzeHeadless" "${probe_root}/project" ArmContext \
|
||||
-import "${probe_root}/arm-thumb.bin" -loader BinaryLoader -processor ARM:LE:32:v7 \
|
||||
-noanalysis -readOnly -deleteProject \
|
||||
-scriptPath "${GITHUB_WORKSPACE}/tests/conformance/ghidra;${GITHUB_WORKSPACE}/bridge/ghidra" \
|
||||
-postScript ReaArmContextProbe.java "${GITHUB_WORKSPACE}/bridge/ghidra" \
|
||||
> "${probe_root}/output.log" 2>&1 || { cat "${probe_root}/output.log"; exit 1; }
|
||||
cat "${probe_root}/output.log"
|
||||
grep -F 'REA_ARM_CONTEXT_OK arm=0 thumb=1 unavailable=null (injected provider value)' "${probe_root}/output.log"
|
||||
@@ -0,0 +1,97 @@
|
||||
name: Real APK signature inspection
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build_cache_artifact:
|
||||
description: Portable build cache artifact from the calling CI run.
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
remote_cache_write:
|
||||
description: Trusted release qualification may publish the remote cache.
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
secrets:
|
||||
TURBO_TOKEN:
|
||||
description: Remote cache token. Only trusted callers pass it.
|
||||
required: false
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
HUSKY: "0"
|
||||
# A called workflow sees the caller event, so workflow_call is not an event
|
||||
# name here. Writes when remote_cache_write is set, or on the default branch
|
||||
# for push, schedule, and manual dispatch. Open pull requests stay empty-token
|
||||
# and use the local cache only.
|
||||
TURBO_TOKEN: "${{ (inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'))) && secrets.TURBO_TOKEN || '' }}"
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
TURBO_CACHE: "${{ (inputs.remote_cache_write == true || (github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'))) && 'local:rw,remote:rw' || 'local:rw' }}"
|
||||
NODE_OPTIONS: "--max-old-space-size=768"
|
||||
RAYON_NUM_THREADS: "1"
|
||||
GOMAXPROCS: "2"
|
||||
UV_THREADPOOL_SIZE: "2"
|
||||
JAVA_TOOL_OPTIONS: "-Xmx512m -XX:ActiveProcessorCount=2"
|
||||
|
||||
jobs:
|
||||
real-apk-signature:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 12
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
- name: Cache npm package downloads
|
||||
id: npm-cache
|
||||
uses: ./.github/actions/npm-cache
|
||||
- run: npm ci
|
||||
- uses: ./.github/actions/portable-build-cache
|
||||
with:
|
||||
build_cache_artifact: ${{ inputs.build_cache_artifact }}
|
||||
- name: Prepare pinned SDK oracle without installing host software
|
||||
shell: bash
|
||||
run: |
|
||||
python3 - <<'PYTHON'
|
||||
import hashlib, os, urllib.request, zipfile
|
||||
from pathlib import Path
|
||||
root = Path(os.environ["RUNNER_TEMP"]) / "rea-apk-signature-sdk"
|
||||
packages = [
|
||||
("build-tools_r36.1_linux.zip", "a7b5889e4a79fcf3b0976bef40d401f4240fb1eed891d9d91169da1111e11d78", 64195204, "build-tools/36.1.0", {"apksigner", "aapt2", "lib/apksigner.jar", "source.properties"}),
|
||||
("platform-36_r02.zip", "37607369a28c5b640b3a7998868d45898ebcb777565a0e85f9acf36f29631d2e", 65878410, "platforms/android-36", {"android.jar", "source.properties"}),
|
||||
]
|
||||
for name, expected, expected_size, directory, selected in packages:
|
||||
archive = root / name
|
||||
archive.parent.mkdir(parents=True, exist_ok=True)
|
||||
digest = hashlib.sha256()
|
||||
total = 0
|
||||
with urllib.request.urlopen("https://dl.google.com/android/repository/" + name, timeout=60) as response, archive.open("wb") as output:
|
||||
while chunk := response.read(1024 * 1024):
|
||||
total += len(chunk)
|
||||
if total > expected_size:
|
||||
raise RuntimeError("SDK archive exceeds the pinned package size budget")
|
||||
digest.update(chunk)
|
||||
output.write(chunk)
|
||||
if total != expected_size or digest.hexdigest() != expected:
|
||||
raise RuntimeError("SDK oracle archive digest mismatch")
|
||||
extracted = set()
|
||||
with zipfile.ZipFile(archive) as source:
|
||||
for entry in source.infolist():
|
||||
relative = entry.filename.partition("/")[2]
|
||||
if relative not in selected:
|
||||
continue
|
||||
target = root / directory / relative
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
target.write_bytes(source.read(entry))
|
||||
target.chmod((entry.external_attr >> 16) & 0o777 or 0o644)
|
||||
extracted.add(relative)
|
||||
if extracted != selected:
|
||||
raise RuntimeError("Pinned SDK package is missing required oracle files")
|
||||
with Path(os.environ["GITHUB_ENV"]).open("a") as environment:
|
||||
environment.write("ANDROID_HOME=" + str(root) + "\n")
|
||||
PYTHON
|
||||
- run: npm run verify:apk-signature -- --require-tools
|
||||
@@ -315,6 +315,9 @@ jobs:
|
||||
|
||||
rehearsal:
|
||||
name: Rehearse qualified release on a clean runner
|
||||
env:
|
||||
TURBO_TOKEN: ""
|
||||
TURBO_CACHE: local:rw
|
||||
needs: [merged-release, release-please, qualification]
|
||||
if: >-
|
||||
always() && !cancelled() && needs.qualification.result == 'success'
|
||||
@@ -348,6 +351,9 @@ jobs:
|
||||
always() && !cancelled() &&
|
||||
needs.qualification.result == 'success' && needs.rehearsal.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TURBO_TOKEN: ""
|
||||
TURBO_CACHE: local:rw
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
@@ -356,41 +362,56 @@ jobs:
|
||||
with:
|
||||
ref: ${{ needs.merged-release.outputs.sha || needs.release-please.outputs.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
package-manager-cache: false
|
||||
registry-url: https://registry.npmjs.org
|
||||
- name: Download the original qualified package
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: verified-release-package
|
||||
path: .cache/verified-package/
|
||||
- name: Bind publication to qualified intent
|
||||
id: package
|
||||
run: node scripts/ci/prepare-npm-publication.mjs
|
||||
- name: Publish
|
||||
if: steps.package.outputs.published == 'false'
|
||||
env:
|
||||
NPM_RELEASE_TAG: ${{ steps.package.outputs.tag }}
|
||||
run: >-
|
||||
npm publish .cache/verified-package/package.tgz --ignore-scripts
|
||||
--registry=https://registry.npmjs.org --access=public --tag="$NPM_RELEASE_TAG"
|
||||
|
||||
verify-npm:
|
||||
name: Verify published npm package
|
||||
needs: [merged-release, release-please, publish]
|
||||
if: >-
|
||||
always() && !cancelled() && needs.publish.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TURBO_TOKEN: ""
|
||||
TURBO_CACHE: local:rw
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
||||
with:
|
||||
ref: ${{ needs.merged-release.outputs.sha || needs.release-please.outputs.sha }}
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
package-manager-cache: false
|
||||
- run: npm ci
|
||||
|
||||
- uses: ./.github/actions/prepare-release-package
|
||||
id: package
|
||||
|
||||
- name: Inspect existing npm version
|
||||
id: registry
|
||||
env:
|
||||
VERIFIED_PACKAGE_TARBALL: ${{ steps.package.outputs.tarball }}
|
||||
VERIFIED_PACKAGE_VERSION: ${{ steps.package.outputs.version }}
|
||||
run: node scripts/ci/npm-release.mjs inspect "$VERIFIED_PACKAGE_TARBALL" "$VERIFIED_PACKAGE_VERSION"
|
||||
|
||||
- name: Publish
|
||||
if: steps.registry.outputs.published == 'false'
|
||||
shell: bash
|
||||
env:
|
||||
VERIFIED_PACKAGE_TARBALL: ${{ steps.package.outputs.tarball }}
|
||||
VERIFIED_PACKAGE_VERSION: ${{ steps.package.outputs.version }}
|
||||
run: |
|
||||
tag="$(node scripts/release-npm-tag.mjs "$VERIFIED_PACKAGE_VERSION")"
|
||||
npm publish "${VERIFIED_PACKAGE_TARBALL}" --access public --tag "${tag}"
|
||||
|
||||
- name: Verify published npm bytes and dist-tag
|
||||
env:
|
||||
VERIFIED_PACKAGE_TARBALL: ${{ steps.package.outputs.tarball }}
|
||||
VERIFIED_PACKAGE_VERSION: ${{ steps.package.outputs.version }}
|
||||
run: node scripts/ci/npm-release.mjs verify "$VERIFIED_PACKAGE_TARBALL" "$VERIFIED_PACKAGE_VERSION"
|
||||
|
||||
- name: Verify published CLI from npm
|
||||
env:
|
||||
VERIFIED_PACKAGE_VERSION: ${{ steps.package.outputs.version }}
|
||||
@@ -398,9 +419,12 @@ jobs:
|
||||
|
||||
publish-mcp:
|
||||
name: Publish to MCP Registry
|
||||
needs: [merged-release, release-please, publish]
|
||||
env:
|
||||
TURBO_TOKEN: ""
|
||||
TURBO_CACHE: local:rw
|
||||
needs: [merged-release, release-please, verify-npm]
|
||||
if: >-
|
||||
always() && !cancelled() && needs.publish.result == 'success' &&
|
||||
always() && !cancelled() && needs.verify-npm.result == 'success' &&
|
||||
((needs.merged-release.result == 'success' && needs.merged-release.outputs.release_created == 'true') ||
|
||||
(needs.release-please.result == 'success' && inputs.phase == 'publish' && needs.release-please.outputs.release_created == 'true'))
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
# Exercise unavailable-runtime diagnostics, the first supported release,
|
||||
# and new patches on both supported lines without hand-editing versions.
|
||||
# The repository-pinned Node 24 version also runs the complete test suite.
|
||||
node: ["22.x", "24.15.0", "24.x", "26.x"]
|
||||
node: ["22.x", "24.22.1", "24.x", "26.x"]
|
||||
steps:
|
||||
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
|
||||
@@ -22,6 +22,8 @@ Keep proof of ownership separate from validity, editability, and readiness. Malf
|
||||
|
||||
For lifecycle changes, follow [ownership and completion invariants](docs/tool-design.md#own-the-lifecycle) and select the applicable [lifecycle regressions](docs/testing.md#lifecycle-regressions). Include late handshakes, cancellation during final cleanup, mixed child outcomes, and cleanup retry where those stages exist; active-execution cancellation alone does not cover finalization.
|
||||
|
||||
Before adding complexity for a speculative or vanishingly unlikely race or security edge case, explain the concrete failure mode, likelihood, and complexity cost to the user and get their buy-in. Do not silently expand scope for theoretical robustness.
|
||||
|
||||
Assess brittleness in touched code during implementation, debugging, review, and maintenance. Fix the producing representation or ownership rule before adding downstream repairs. Normalize once at the owning boundary using format-aware parsers. Remove superseded representations, aliases, wrappers, and redundant tests after verifying affected consumers. Introduce abstractions only when they remove observed complexity.
|
||||
|
||||
When fixing a bug, inspect the producing boundary and affected consumers for duplicated interpretation or unclear ownership. Complete any directly related refactor in the same change and remove superseded code. Passing regression tests alone does not establish that the brittleness is resolved. If related cleanup remains, explain what remains and why.
|
||||
@@ -59,7 +61,7 @@ do not establish fewer tokens or faster analysis.
|
||||
|
||||
## Development
|
||||
|
||||
Use [.nvmrc](.nvmrc) and `package.json#packageManager` for the pinned toolchain. Cursor Cloud may place older Node.js first on `PATH`; environment setup installs the pinned toolchain under `/usr/local/bin`.
|
||||
Use [.nvmrc](.nvmrc) and `package.json#packageManager` for the pinned toolchain. Cursor Cloud may place older Node.js first on `PATH`; environment setup installs the pinned toolchain under `/usr/local/bin`. Prefix `PATH="/usr/local/bin:$PATH"` before `node` and `npm`.
|
||||
|
||||
- `npm ci`: install locked dependencies.
|
||||
- `npm run build:cached`: build the runtime and packaged skill.
|
||||
@@ -70,6 +72,8 @@ Use [.nvmrc](.nvmrc) and `package.json#packageManager` for the pinned toolchain.
|
||||
|
||||
Use relevant checks for the change. The complete local gate, `npm run check:pr`, is optional for broad changes or CI diagnosis. See [CONTRIBUTING.md](CONTRIBUTING.md) for development, generated-file ownership, and release conventions.
|
||||
|
||||
Coordinate expensive checks across agents. If a test unexpectedly consumes heavy CPU, stop its owned process family and profile a bounded representative case before retrying. Inspect production work, fixture generation, subprocesses, and repeated setup; preserve regression coverage when optimizing. Follow the [test resource guidance](docs/testing.md#developer-commands).
|
||||
|
||||
`docs/public/product-catalog.json`, `docs/verification/managed-conformance-*.json`, and `skills/` are ignored outputs. Edit source contracts and `.agents/skills/reverse-engineer-anything/`, then regenerate as needed. `.cache/mcp-tool-catalog.json` is test metadata; runtime builds and source checking do not consume it. Never commit binaries, provider project documents, credentials, `dist/`, `node_modules/`, or local planning artifacts.
|
||||
|
||||
## Tool and Test Changes
|
||||
|
||||
@@ -26,6 +26,8 @@ to locate provider and shared-workflow bottlenecks, preserve Evidence, and
|
||||
compare equivalent real tasks before claiming an improvement.
|
||||
|
||||
When adding or changing an MCP tool, follow the [tool design guide](docs/tool-design.md) and preserve the canonical contracts and generated catalog.
|
||||
When adding or changing an admission ceiling, budget, or deadline, follow
|
||||
[admission limits and recovery](docs/design/limits-and-recovery.md).
|
||||
|
||||
## Reporting issues
|
||||
|
||||
@@ -239,6 +241,19 @@ MinGW-w64, and `tar`; the build script does not run on Windows. See that guide
|
||||
for the build and artifact-verification commands and the separate real Windows
|
||||
verification prerequisites. Keep the generated addon and manifest uncommitted.
|
||||
|
||||
The general source suite (`npm run test:fast`, `npm run test:changed`, and
|
||||
`npm run test:local`) runs on Linux in CI, and Windows CI runs a curated lane.
|
||||
On a Windows checkout, some source tests fail because fixtures use POSIX paths,
|
||||
`#!/bin/sh` tool stubs, or POSIX rename semantics. Compare failures against the
|
||||
base revision, or run the suite on Linux or WSL, before attributing them to a
|
||||
change. See [testing](docs/testing.md#developer-commands) for command scopes
|
||||
and lane selection.
|
||||
|
||||
`git submodule update --init --recursive` fails at the pinned Unblob submodule
|
||||
on Windows and can leave later submodules unchecked out. Apply the
|
||||
[Unblob checkout workaround](docs/firmware-analysis.md#windows-submodule-checkout),
|
||||
then rerun the command.
|
||||
|
||||
## Documentation website
|
||||
|
||||
The VitePress site uses the Markdown files in `docs/`. Run `npm run docs:dev`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
**English** · [简体中文](docs/readme/README_zh.md) · [繁體中文](docs/readme/README_zh-TW.md) · [日本語](docs/readme/README_ja.md) · [한국어](docs/readme/README_ko.md) · [Türkçe](docs/readme/README_tr.md) · [Русский](docs/readme/README_ru.md) · [Tiếng Việt](docs/readme/README_vi.md) · [ไทย](docs/readme/README_th.md) · [Deutsch](docs/readme/README_de.md) · [Español](docs/readme/README_es.md) · [Français](docs/readme/README_fr.md) · [Українська](docs/readme/README_uk.md) · [Polski](docs/readme/README_pl.md) · [Português (Brasil)](docs/readme/README_pt-BR.md) · [العربية](docs/readme/README_ar.md) · [فارسی](docs/readme/README_fa.md) · [Bahasa Indonesia](docs/readme/README_id.md) · [Italiano](docs/readme/README_it.md)
|
||||
· [Ελληνικά](docs/readme/README_el.md) · [മലയാളം](docs/readme/README_ml.md)
|
||||
· [Ελληνικά](docs/readme/README_el.md) · [മലയാളം](docs/readme/README_ml.md) · [Roman Urdu](docs/readme/README_ur-Latn.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -177,7 +177,7 @@ CLI commands use the same workflows.
|
||||
|
||||
## What you can analyze
|
||||
|
||||
REA requires Node.js 22.x (>=22.19), 24.x (>=24.11), or 26+, plus npm.
|
||||
REA requires Node.js 22.x (>=22.23.4), 24.x (>=24.22.1), or 26.12.1+, plus npm.
|
||||
Additional tools and host support depend on the target:
|
||||
|
||||
| Target | What REA returns | Requirements and guide |
|
||||
@@ -191,6 +191,9 @@ Additional tools and host support depend on the target:
|
||||
| IL2CPP metadata | Unity global-metadata.dat assembly images, type and method names and index ranges | Built-in static decoding of versions 24, 27, 29, 31 and 39; no Unity required |
|
||||
| Godot PCK | Archive inventory and extraction, original header/directory facts and selected content identities | Built-in static formats 2, 3 and 4; no Godot required |
|
||||
| Rust binaries | Embedded cargo-auditable crate names, versions, sources and dependency edges | Built-in static ELF/PE/thin Mach-O inspection; [Rust binaries](docs/rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](docs/pe-certificates.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](docs/elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, imports, lambdas and the Code header | Built-in static BEAM inspection; [Erlang BEAM](docs/erlang-beam.md) |
|
||||
| WASM artifact | Validation, sections, exact import/export WAT forms and decoded WAT | Caller-supplied WABT 1.0.42; `inspect_wasm_artifact` |
|
||||
| EVM bytecode | Dispatch selectors, byte offsets, inferred arguments and mutability | Local raw/hex carrier on Linux x64; [offline EVM guide](docs/evm-bytecode.md) |
|
||||
| SQLite databases | Tables, columns, indexes, views, triggers and selected ordinary-table rows | Local database/WAL snapshot; Node.js 24.x >=24.15 or 26+ with native SQLite limits |
|
||||
@@ -200,6 +203,7 @@ Additional tools and host support depend on the target:
|
||||
| Saved network captures | Requests, responses, exposed payloads and source locations | HAR or Fiddler Everywhere SAZ; mitmdump on Linux for native mitmproxy; [capture guide](docs/web-network-captures.md) |
|
||||
| .NET assemblies | Metadata, CIL instructions, declared native dependencies and build comparisons | None (static only); [managed-code guide](docs/managed-code-analysis.md) |
|
||||
| Android APKs | Manifest declarations, classes, decompiled methods and references | Headless JADX and a full JDK on Linux/macOS/Windows x64; [Android guide](docs/android-analysis.md) |
|
||||
| APK signatures | v1/v2/v3/v3.1 signers, certificate fingerprints, key rotation and digest self-consistency | None (static only); `inspect_apk_signature` |
|
||||
| Android devices | Devices, packages, processes, logs, dumps, screen captures, and APK/file transfers | Caller-supplied adb (emulator or hardware); [ADB guide](docs/adb-device-analysis.md) |
|
||||
| JEB projects | Engine-backed project units, artifact digests and type/method pseudo-code | A caller-started JEB client serving MCP, selected with REA_JEB_MCP_URL; [JEB guide](docs/jeb-analysis.md) |
|
||||
| Android resources | Decoded manifest, string tables, locales and version facts | Caller-supplied Apktool launcher; [resource guide](docs/apktool-resource-analysis.md) |
|
||||
|
||||
@@ -10,6 +10,7 @@ import jadx.api.plugins.input.insns.Opcode;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.nodes.*;
|
||||
import java.io.PrintStream;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@@ -23,6 +24,10 @@ import kotlin.coroutines.intrinsics.IntrinsicsKt;
|
||||
import kotlinx.coroutines.BuildersKt;
|
||||
import kotlinx.io.CoreKt;
|
||||
import kotlinx.io.JvmCoreKt;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
/** REA-owned metadata boundary for the unmodified jadx-headless-mcp 0.7.1 JAR. */
|
||||
class ReaJadxBridge {
|
||||
@@ -30,10 +35,13 @@ class ReaJadxBridge {
|
||||
private final SessionHolder holder;
|
||||
private JadxSession indexedSession;
|
||||
private Map<String, List<ClassSnapshot>> classes = Map.of();
|
||||
private JadxSession manifestSession;
|
||||
private ManifestSnapshot manifestSnapshot;
|
||||
|
||||
private record MethodSnapshot(String name, String rawName, String shortId, List<String> bodyAbsenceMarkers,
|
||||
Map<String, Object> summary) {}
|
||||
private record ClassSnapshot(JavaClass node, List<MethodSnapshot> methods, Map<String, Object> summary) {}
|
||||
private record ManifestSnapshot(String text, Map<String, Object> summary) {}
|
||||
|
||||
private static final class InputFailure extends IllegalArgumentException {
|
||||
final String field;
|
||||
@@ -93,6 +101,7 @@ class ReaJadxBridge {
|
||||
args.has("threads") ? integer(args, "threads", 1) : null,
|
||||
args.has("code_cache_size") ? integer(args, "code_cache_size", 64) : null,
|
||||
optionalString(args, "resources"));
|
||||
clearManifest();
|
||||
return loadCall(next -> holder.load(path, options, next), continuation);
|
||||
}
|
||||
|
||||
@@ -153,6 +162,77 @@ class ReaJadxBridge {
|
||||
return current;
|
||||
}
|
||||
|
||||
private void clearManifest() {
|
||||
manifestSession = null;
|
||||
manifestSnapshot = null;
|
||||
}
|
||||
|
||||
/** Original archive identity, never a deobfuscated basename or name suffix. */
|
||||
private ManifestSnapshot manifest(JadxSession current) {
|
||||
if (manifestSession != current || manifestSnapshot == null) {
|
||||
ResourceFile selected = null;
|
||||
for (ResourceFile resource : current.getResources()) {
|
||||
if (resource.getType() != ResourceType.MANIFEST
|
||||
|| !resource.getOriginalName().equals("AndroidManifest.xml")) continue;
|
||||
if (selected != null)
|
||||
throw new IllegalArgumentException("Root AndroidManifest.xml resource identity is ambiguous");
|
||||
selected = resource;
|
||||
}
|
||||
if (selected == null) throw new IllegalArgumentException("Root AndroidManifest.xml not found");
|
||||
var content = selected.loadContent();
|
||||
if (content == null || content.getDataType() != jadx.core.xmlgen.ResContainer.DataType.TEXT)
|
||||
throw new IllegalArgumentException("Root AndroidManifest.xml did not decode as text");
|
||||
String xml = content.getText().getCodeStr();
|
||||
ManifestSnapshot snapshot = new ManifestSnapshot(xml, manifestSummary(xml));
|
||||
manifestSnapshot = snapshot;
|
||||
manifestSession = current;
|
||||
}
|
||||
return manifestSnapshot;
|
||||
}
|
||||
|
||||
/** One parsed XML owner supplies namespace-aware values alongside the exact decoded text. */
|
||||
static Map<String, Object> manifestSummary(String xml) {
|
||||
Element root;
|
||||
try {
|
||||
// Match REA's existing JDK XML setup: document types are unsupported.
|
||||
// Parse an in-memory string; XInclude and external DTD/schema I/O stay disabled.
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newDefaultNSInstance();
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
factory.setXIncludeAware(false);
|
||||
factory.setAttribute(javax.xml.XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
||||
factory.setAttribute(javax.xml.XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
|
||||
root = factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)))
|
||||
.getDocumentElement();
|
||||
} catch (javax.xml.parsers.ParserConfigurationException | org.xml.sax.SAXException
|
||||
| java.io.IOException failure) {
|
||||
throw new IllegalArgumentException("Root AndroidManifest.xml is not supported well-formed XML", failure);
|
||||
}
|
||||
if (!root.getTagName().equals("manifest") || root.getNamespaceURI() != null)
|
||||
throw new IllegalArgumentException("AndroidManifest.xml root must be an unnamespaced <manifest>");
|
||||
String android = "http://schemas.android.com/apk/res/android";
|
||||
String minSdk = "";
|
||||
String targetSdk = "";
|
||||
List<String> permissions = new ArrayList<>();
|
||||
for (Node child = root.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (!(child instanceof Element element) || element.getNamespaceURI() != null) continue;
|
||||
if (element.getTagName().equals("uses-sdk")) {
|
||||
minSdk = element.getAttributeNS(android, "minSdkVersion");
|
||||
targetSdk = element.getAttributeNS(android, "targetSdkVersion");
|
||||
} else if (element.getTagName().equals("uses-permission")) {
|
||||
String permission = element.getAttributeNS(android, "name");
|
||||
if (!permission.isEmpty()) permissions.add(permission);
|
||||
}
|
||||
}
|
||||
Map<String, Object> summary = new LinkedHashMap<>();
|
||||
summary.put("package", root.getAttribute("package"));
|
||||
summary.put("version_name", root.getAttributeNS(android, "versionName"));
|
||||
summary.put("version_code", root.getAttributeNS(android, "versionCode"));
|
||||
summary.put("min_sdk", minSdk);
|
||||
summary.put("target_sdk", targetSdk);
|
||||
summary.put("permissions", List.copyOf(permissions));
|
||||
return Collections.unmodifiableMap(summary);
|
||||
}
|
||||
|
||||
private ClassSnapshot selected(JsonObject args) {
|
||||
JadxSession current = session();
|
||||
if (indexedSession != current) {
|
||||
@@ -333,6 +413,9 @@ class ReaJadxBridge {
|
||||
"java_version", System.getProperty("java.version"),
|
||||
"metadata_scope", "parsed_members"));
|
||||
JadxSession current = session();
|
||||
if (name.equals("get_app_info")) return json(manifest(current).summary());
|
||||
if (name.equals("get_android_manifest"))
|
||||
return text(TextUtilKt.truncateToBytes(manifest(current).text(), current.getMaxSourceBytes()), false);
|
||||
if (name.equals("list_classes")) {
|
||||
List<String> names = current.getClassFqns();
|
||||
String query = args.has("query") ? string(args, "query") : "";
|
||||
@@ -420,6 +503,17 @@ class ReaJadxBridge {
|
||||
return json(result);
|
||||
}
|
||||
|
||||
private static void registerBridgeTool(Server server, ReaJadxBridge bridge, String name,
|
||||
ToolSchema schema, String description) {
|
||||
Tool tool = new Tool(name, schema, description, null, null, null, null, null, null);
|
||||
server.addTool(tool, (connection, request, continuation) -> {
|
||||
try { return bridge.handle(name, request.getArguments()); }
|
||||
catch (InputFailure error) { return text(JSON.toJson(Map.of(
|
||||
"kind", "invalid-input", "field", error.field, "message", error.getMessage())), true); }
|
||||
catch (IllegalArgumentException error) { return text(error.getMessage(), true); }
|
||||
});
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
PrintStream protocolOut = System.out;
|
||||
System.setOut(System.err);
|
||||
@@ -428,10 +522,9 @@ class ReaJadxBridge {
|
||||
SessionHolder holder = new SessionHolder(defaults);
|
||||
ServerCapabilities capabilities = new ServerCapabilities(
|
||||
new ServerCapabilities.Tools(null), null, null, null, null, null, null, Map.of());
|
||||
Server server = new Server(new Implementation("rea-jadx-bridge", "4", null, null, null),
|
||||
Server server = new Server(new Implementation("rea-jadx-bridge", "5", null, null, null),
|
||||
new ServerOptions(capabilities), "", ignored -> Unit.INSTANCE);
|
||||
SessionToolsKt.registerSessionTools(server, holder);
|
||||
ManifestToolsKt.registerManifestTools(server, holder);
|
||||
ClassToolsKt.registerClassTools(server, holder);
|
||||
MethodToolsKt.registerMethodTools(server, holder);
|
||||
XrefToolsKt.registerXrefTools(server, holder);
|
||||
@@ -440,7 +533,7 @@ class ReaJadxBridge {
|
||||
server.removeTool("load_apk");
|
||||
server.addTool(loadTool, (connection, request, continuation) ->
|
||||
bridge.load(request.getArguments(), defaults, continuation));
|
||||
Set<String> consumed = Set.of("load_apk", "get_app_info", "get_android_manifest",
|
||||
Set<String> consumed = Set.of("load_apk",
|
||||
"list_classes", "get_class_summary", "get_method_body",
|
||||
"get_xrefs_to_class", "get_xrefs_to_method");
|
||||
for (String name : new ArrayList<>(server.getTools().keySet()))
|
||||
@@ -449,6 +542,13 @@ class ReaJadxBridge {
|
||||
new ToolSchema(null, new kotlinx.serialization.json.JsonObject(Map.of()), List.of(), null),
|
||||
"Observed worker JVM and metadata scope", null, null, null, null, null, null);
|
||||
server.addTool(diagnostics, (connection, request, continuation) -> bridge.handle("rea_jvm_status", request.getArguments()));
|
||||
for (String name : List.of("get_app_info", "get_android_manifest")) {
|
||||
String description = name.equals("get_app_info")
|
||||
? "Namespace-aware summary of the exact root AndroidManifest.xml resource."
|
||||
: "Exact decoded root AndroidManifest.xml text, bounded by the session source byte limit.";
|
||||
registerBridgeTool(server, bridge, name,
|
||||
new ToolSchema(null, new kotlinx.serialization.json.JsonObject(Map.of()), List.of(), null), description);
|
||||
}
|
||||
for (String name : List.of("list_classes", "get_class_summary",
|
||||
"get_method_body", "get_xrefs_to_class", "get_xrefs_to_method")) {
|
||||
Tool tool = server.getTools().get(name).getTool();
|
||||
@@ -470,14 +570,9 @@ class ReaJadxBridge {
|
||||
case "get_method_body" -> "Source for an exact class and stable same-name overload index; static initializers use smali to preserve folded field initialization.";
|
||||
default -> "Complete static using-node inventory for an exact class or selected method overload; one node may contain multiple invoke instructions, and source lines are unresolved.";
|
||||
};
|
||||
Tool narrowed = new Tool(name, new ToolSchema(null, new kotlinx.serialization.json.JsonObject(properties),
|
||||
tool.getInputSchema().getRequired(), null), description, null, null, null, null, null, null);
|
||||
server.addTool(narrowed, (connection, request, continuation) -> {
|
||||
try { return bridge.handle(name, request.getArguments()); }
|
||||
catch (InputFailure error) { return text(JSON.toJson(Map.of(
|
||||
"kind", "invalid-input", "field", error.field, "message", error.getMessage())), true); }
|
||||
catch (IllegalArgumentException error) { return text(error.getMessage(), true); }
|
||||
});
|
||||
registerBridgeTool(server, bridge, name,
|
||||
new ToolSchema(null, new kotlinx.serialization.json.JsonObject(properties),
|
||||
tool.getInputSchema().getRequired(), null), description);
|
||||
}
|
||||
CountDownLatch done = new CountDownLatch(1);
|
||||
server.onClose(() -> { done.countDown(); return Unit.INSTANCE; });
|
||||
@@ -503,6 +598,7 @@ class ReaJadxBridge {
|
||||
BuildersKt.runBlocking(EmptyCoroutineContext.INSTANCE,
|
||||
(scope, continuation) -> server.close(continuation));
|
||||
} finally {
|
||||
bridge.clearManifest();
|
||||
BuildersKt.runBlocking(EmptyCoroutineContext.INSTANCE,
|
||||
(scope, continuation) -> holder.unload(continuation));
|
||||
}
|
||||
|
||||
+604
-99
@@ -11,6 +11,7 @@ import json
|
||||
import hashlib
|
||||
import hmac
|
||||
import os
|
||||
import re
|
||||
import secrets
|
||||
import socket
|
||||
import stat
|
||||
@@ -33,9 +34,151 @@ except ImportError:
|
||||
from PySide2.QtCore import QCoreApplication, QObject, Signal
|
||||
|
||||
|
||||
MAX_FRAME_BYTES = 16 * 1024 * 1024
|
||||
# Request and response frame budget in bytes, excluding the trailing LF.
|
||||
# REA_BRIDGE_MAX_REQUEST_BYTES selects it. Unset stays 16777216.
|
||||
# 7464 is the authenticated frame of the largest bounded symbol name.
|
||||
# The 64-receipt recovery status is smaller with current_file null. A path
|
||||
# that fits is kept. A path that does not fit is null, not the descriptor path.
|
||||
# 536870887 is Node's 536870888-character string ceiling minus the framing LF.
|
||||
# The ceiling is the encoded payload; JSON expansion is measured before it.
|
||||
# A fitting response is signed from bounded JSON pieces and written in 64 KiB
|
||||
# chunks, so this maximum does not retain several copies of the frame.
|
||||
_BRIDGE_MAX_REQUEST_BYTES_SETTING = "REA_BRIDGE_MAX_REQUEST_BYTES"
|
||||
DEFAULT_BRIDGE_MAX_REQUEST_BYTES = 16 * 1024 * 1024
|
||||
MINIMUM_BRIDGE_MAX_REQUEST_BYTES = 7464
|
||||
MAXIMUM_BRIDGE_MAX_REQUEST_BYTES = 536870887
|
||||
# The outer authenticated frame around the escaped JSON payload, excluding LF.
|
||||
_AUTHENTICATED_PREFIX = b'{"response":"'
|
||||
_AUTHENTICATED_PROOF_MARK = b'","proof":"'
|
||||
_PROOF_HEX_LENGTH = 64
|
||||
_AUTHENTICATED_FRAME_OVERHEAD = (
|
||||
len(_AUTHENTICATED_PREFIX)
|
||||
+ len(_AUTHENTICATED_PROOF_MARK)
|
||||
+ _PROOF_HEX_LENGTH
|
||||
+ len(b'"}')
|
||||
)
|
||||
_AUTHENTICATED_WRITE_BUFFER_BYTES = 64 * 1024
|
||||
# Raw JSON is produced in pieces no larger than this many characters.
|
||||
# One character expands to at most six JSON bytes (\u00XX) before the outer
|
||||
# string escape, so a piece stays far below the frame ceiling.
|
||||
_JSON_CHUNK_CHARS = 64 * 1024
|
||||
# Fixed admission cap. It does not follow REA_BRIDGE_MAX_REQUEST_BYTES.
|
||||
# A further accept is closed. Starting a worker must not stop the listener.
|
||||
MAX_CONNECTION_WORKERS = 8
|
||||
|
||||
|
||||
def _close_socket(connection: socket.socket) -> None:
|
||||
try:
|
||||
connection.close()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def _bridge_max_request_bytes_constraint():
|
||||
return (
|
||||
"REA_BRIDGE_MAX_REQUEST_BYTES must be a positive decimal integer "
|
||||
"from %d to %d bytes; the default is %d bytes (16 MiB). "
|
||||
"A value below %d bytes cannot carry the largest admitted "
|
||||
"symbol-name command, and a larger value is refused so the encoded "
|
||||
"payload plus its framing LF stays one string under Node's "
|
||||
"single-string ceiling."
|
||||
% (
|
||||
MINIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
MAXIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
DEFAULT_BRIDGE_MAX_REQUEST_BYTES,
|
||||
MINIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _parse_bridge_max_request_bytes(raw):
|
||||
"""Refuse a non-decimal or out-of-range ceiling. Never fall back."""
|
||||
constraint = _bridge_max_request_bytes_constraint()
|
||||
if isinstance(raw, bool):
|
||||
raise RuntimeError(constraint)
|
||||
if isinstance(raw, int):
|
||||
value = raw
|
||||
elif isinstance(raw, str):
|
||||
# ASCII digits only. str.isdigit() accepts numerals such as U+0668
|
||||
# that the TypeScript setting rejects.
|
||||
if re.fullmatch(r"[1-9][0-9]*", raw) is None:
|
||||
raise RuntimeError(constraint)
|
||||
value = int(raw)
|
||||
else:
|
||||
raise RuntimeError(constraint)
|
||||
if (
|
||||
value < MINIMUM_BRIDGE_MAX_REQUEST_BYTES
|
||||
or value > MAXIMUM_BRIDGE_MAX_REQUEST_BYTES
|
||||
):
|
||||
raise RuntimeError(constraint)
|
||||
return value
|
||||
|
||||
|
||||
def _resolve_bridge_max_request_bytes():
|
||||
"""Prefer an injected global, then the process environment, then 16 MiB."""
|
||||
injected = globals().get(_BRIDGE_MAX_REQUEST_BYTES_SETTING)
|
||||
if injected is not None:
|
||||
return _parse_bridge_max_request_bytes(injected), "setting"
|
||||
raw = os.environ.get(_BRIDGE_MAX_REQUEST_BYTES_SETTING)
|
||||
if raw is None:
|
||||
return DEFAULT_BRIDGE_MAX_REQUEST_BYTES, "default"
|
||||
return _parse_bridge_max_request_bytes(raw), "setting"
|
||||
|
||||
|
||||
MAX_FRAME_BYTES, BRIDGE_MAX_REQUEST_BYTES_SOURCE = (
|
||||
_resolve_bridge_max_request_bytes()
|
||||
)
|
||||
|
||||
|
||||
def _bridge_max_request_bytes_recovery():
|
||||
return (
|
||||
"The effective REA_BRIDGE_MAX_REQUEST_BYTES value is %d bytes "
|
||||
"(source %s; default %d, floor %d, maximum %d). "
|
||||
"Set REA_BRIDGE_MAX_REQUEST_BYTES in the environment that starts REA "
|
||||
"to a decimal integer from %d to %d, then restart REA. "
|
||||
"Restart Hopper or Cutter from that same environment so the bridge "
|
||||
"uses this ceiling."
|
||||
% (
|
||||
MAX_FRAME_BYTES,
|
||||
BRIDGE_MAX_REQUEST_BYTES_SOURCE,
|
||||
DEFAULT_BRIDGE_MAX_REQUEST_BYTES,
|
||||
MINIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
MAXIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
MINIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
MAXIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _frame_limit_exceeded():
|
||||
return ValueError(
|
||||
"frame-limit-exceeded: Bridge request exceeds the %d-byte payload limit. %s"
|
||||
% (MAX_FRAME_BYTES, _bridge_max_request_bytes_recovery())
|
||||
)
|
||||
|
||||
|
||||
SOCKET_TIMEOUT_SECONDS = 20
|
||||
AUTH_FRAME_TIMEOUT_SECONDS = 1
|
||||
# The client request deadline. The authenticated frame read may use up to
|
||||
# this long; it does not grow past it when the byte ceiling is raised.
|
||||
REQUEST_DEADLINE_SECONDS = 25
|
||||
|
||||
|
||||
def _authenticated_frame_timeout_seconds():
|
||||
"""Time to hash and transfer one maximum-sized authenticated frame.
|
||||
|
||||
The hello frame stays at one second. The following command frame is
|
||||
built only after that challenge, so its read budget follows the
|
||||
configured payload size, at one second per mebibyte, and never exceeds
|
||||
the 25 second client deadline.
|
||||
"""
|
||||
mebibytes = (MAX_FRAME_BYTES + (1024 * 1024) - 1) // (1024 * 1024)
|
||||
return min(
|
||||
REQUEST_DEADLINE_SECONDS,
|
||||
max(AUTH_FRAME_TIMEOUT_SECONDS, mebibytes),
|
||||
)
|
||||
|
||||
|
||||
MAX_DESCRIPTOR_BYTES = 64 * 1024
|
||||
MAX_COMPLETION_RECEIPTS = 64
|
||||
|
||||
@@ -480,6 +623,17 @@ class _BridgeServer(threading.Thread):
|
||||
self.token = secrets.token_urlsafe(32)
|
||||
self.poisoned = False
|
||||
self.connection_ordinal = 0
|
||||
# The client proof is inside the authenticated frame, so that read
|
||||
# cannot start after proof. It runs off the accept loop. One
|
||||
# authenticated command still runs at a time. completed_connection
|
||||
# is the longest prefix of these ordinals whose handlers have
|
||||
# terminated, not "this status ordinal minus one".
|
||||
self._command_lock = threading.Lock()
|
||||
self._connections_lock = threading.Lock()
|
||||
self._connections: set[socket.socket] = set()
|
||||
self._workers: list[threading.Thread] = []
|
||||
self._finished_through = 0
|
||||
self._finished_ordinals: set[int] = set()
|
||||
self.directory = _bridge_directory()
|
||||
self.descriptor = self.directory / f"cutter-{os.getpid()}-{self.session_id}.json"
|
||||
|
||||
@@ -500,6 +654,7 @@ class _BridgeServer(threading.Thread):
|
||||
"current_file": self.dispatcher.current_file,
|
||||
"cutter_version": self.dispatcher.cutter_version,
|
||||
"identity_status": "partial",
|
||||
"max_request_bytes": MAX_FRAME_BYTES,
|
||||
}
|
||||
if os.name == "nt":
|
||||
_write_windows_descriptor(self.directory, self.descriptor, json.dumps(payload).encode("utf-8"))
|
||||
@@ -541,8 +696,46 @@ class _BridgeServer(threading.Thread):
|
||||
continue
|
||||
except OSError:
|
||||
break
|
||||
with self._connections_lock:
|
||||
self._workers = [
|
||||
worker for worker in self._workers if worker.is_alive()
|
||||
]
|
||||
at_capacity = len(self._workers) >= MAX_CONNECTION_WORKERS
|
||||
if at_capacity:
|
||||
_close_socket(connection)
|
||||
continue
|
||||
self.connection_ordinal += 1
|
||||
connection_ordinal = self.connection_ordinal
|
||||
worker = threading.Thread(
|
||||
target=self._serve_connection,
|
||||
args=(connection, connection_ordinal),
|
||||
name="rea-cutter-bridge-connection",
|
||||
daemon=True,
|
||||
)
|
||||
with self._connections_lock:
|
||||
self._connections.add(connection)
|
||||
self._workers.append(worker)
|
||||
try:
|
||||
worker.start()
|
||||
except RuntimeError:
|
||||
with self._connections_lock:
|
||||
self._connections.discard(connection)
|
||||
if worker in self._workers:
|
||||
self._workers.remove(worker)
|
||||
self._note_connection_finished(connection_ordinal)
|
||||
_close_socket(connection)
|
||||
with self._connections_lock:
|
||||
workers = list(self._workers)
|
||||
for worker in workers:
|
||||
worker.join(timeout=1)
|
||||
self.server.close()
|
||||
try:
|
||||
self.descriptor.unlink(missing_ok=True)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def _serve_connection(self, connection: socket.socket, connection_ordinal: int) -> None:
|
||||
try:
|
||||
with connection:
|
||||
connection.settimeout(AUTH_FRAME_TIMEOUT_SECONDS)
|
||||
authenticated = False
|
||||
@@ -550,60 +743,73 @@ class _BridgeServer(threading.Thread):
|
||||
hello = self._receive_frame(connection)
|
||||
if not isinstance(hello, dict) or hello.get("kind") != "rea-auth-v2" or not isinstance(hello.get("nonce"), str) or len(hello["nonce"]) != 64:
|
||||
self._send(connection, {"ok": False, "error": "authentication-failed"})
|
||||
continue
|
||||
return
|
||||
client_nonce = hello["nonce"]
|
||||
server_nonce = f"{connection_ordinal:016x}{secrets.token_hex(24)}"
|
||||
server_proof = hmac.new(self.token.encode(), f"rea-cutter-server-v2:{self.session_id}:{client_nonce}:{server_nonce}".encode(), hashlib.sha256).hexdigest()
|
||||
self._send(connection, {"session_id": self.session_id, "nonce": server_nonce, "proof": server_proof})
|
||||
authenticated_frame = self._receive_frame(connection)
|
||||
authenticated_frame = self._receive_frame(
|
||||
connection, _authenticated_frame_timeout_seconds()
|
||||
)
|
||||
request_bytes = authenticated_frame.get("request") if isinstance(authenticated_frame, dict) else None
|
||||
expected_proof = hmac.new(self.token.encode(), f"rea-cutter-client-v2:{self.session_id}:{client_nonce}:{server_nonce}:{request_bytes}".encode(), hashlib.sha256).hexdigest()
|
||||
if not isinstance(request_bytes, str) or not isinstance(authenticated_frame.get("proof"), str) or not hmac.compare_digest(authenticated_frame["proof"], expected_proof):
|
||||
presented_proof = authenticated_frame.get("proof") if isinstance(authenticated_frame, dict) else None
|
||||
if not isinstance(request_bytes, str) or not isinstance(presented_proof, str):
|
||||
self._send(connection, {"ok": False, "error": "authentication-failed"})
|
||||
continue
|
||||
return
|
||||
# Update the prefix and the request separately. One joined
|
||||
# preimage would retain another copy of a maximum-sized command.
|
||||
expected_proof = hmac.new(self.token.encode(), digestmod=hashlib.sha256)
|
||||
expected_proof.update(
|
||||
f"rea-cutter-client-v2:{self.session_id}:{client_nonce}:{server_nonce}:".encode()
|
||||
)
|
||||
expected_proof.update(request_bytes.encode())
|
||||
if not hmac.compare_digest(presented_proof, expected_proof.hexdigest()):
|
||||
self._send(connection, {"ok": False, "error": "authentication-failed"})
|
||||
return
|
||||
request = json.loads(request_bytes)
|
||||
if not isinstance(request, dict) or request.get("session_id") != self.session_id:
|
||||
self._send(connection, {"ok": False, "error": "authentication-failed"})
|
||||
continue
|
||||
return
|
||||
authenticated = True
|
||||
connection.settimeout(SOCKET_TIMEOUT_SECONDS)
|
||||
if self.poisoned and request.get("kind") not in ("status", "ack"):
|
||||
self._send_authenticated(connection, {
|
||||
"ok": False,
|
||||
"error": "session-poisoned-after-ui-timeout",
|
||||
"execution_state": "not_started",
|
||||
}, client_nonce, server_nonce)
|
||||
continue
|
||||
if (
|
||||
request.get("kind") == "command"
|
||||
and not self.dispatcher.can_accept_command()
|
||||
):
|
||||
self._send_authenticated(connection, {
|
||||
"ok": False,
|
||||
"error": "completion-receipt-capacity-exceeded",
|
||||
"execution_state": "not_started",
|
||||
}, client_nonce, server_nonce)
|
||||
continue
|
||||
request["session_id"] = self.session_id
|
||||
event = threading.Event()
|
||||
cancelled = threading.Event()
|
||||
reply: dict[str, Any] = {}
|
||||
request["_event"] = event
|
||||
request["_cancelled"] = cancelled
|
||||
self.dispatcher.dispatch.emit(request, reply)
|
||||
if not event.wait(SOCKET_TIMEOUT_SECONDS):
|
||||
cancelled.set()
|
||||
self.poisoned = True
|
||||
self._send_authenticated(connection, {
|
||||
"ok": False,
|
||||
"error": "ui-thread-request-timeout",
|
||||
"execution_state": "unknown",
|
||||
"message": "The UI operation may still complete after this timeout; restart Cutter before issuing further commands.",
|
||||
}, client_nonce, server_nonce)
|
||||
else:
|
||||
if request.get("kind") == "status" and reply.get("ok") is True:
|
||||
reply["completed_connection"] = f"{connection_ordinal - 1:016x}"
|
||||
self._send_authenticated(connection, reply, client_nonce, server_nonce)
|
||||
with self._command_lock:
|
||||
connection.settimeout(SOCKET_TIMEOUT_SECONDS)
|
||||
if self.poisoned and request.get("kind") not in ("status", "ack"):
|
||||
self._send_authenticated(connection, {
|
||||
"ok": False,
|
||||
"error": "session-poisoned-after-ui-timeout",
|
||||
"execution_state": "not_started",
|
||||
}, client_nonce, server_nonce)
|
||||
return
|
||||
if (
|
||||
request.get("kind") == "command"
|
||||
and not self.dispatcher.can_accept_command()
|
||||
):
|
||||
self._send_authenticated(connection, {
|
||||
"ok": False,
|
||||
"error": "completion-receipt-capacity-exceeded",
|
||||
"execution_state": "not_started",
|
||||
}, client_nonce, server_nonce)
|
||||
return
|
||||
request["session_id"] = self.session_id
|
||||
event = threading.Event()
|
||||
cancelled = threading.Event()
|
||||
reply: dict[str, Any] = {}
|
||||
request["_event"] = event
|
||||
request["_cancelled"] = cancelled
|
||||
self.dispatcher.dispatch.emit(request, reply)
|
||||
if not event.wait(SOCKET_TIMEOUT_SECONDS):
|
||||
cancelled.set()
|
||||
self.poisoned = True
|
||||
self._send_authenticated(connection, {
|
||||
"ok": False,
|
||||
"error": "ui-thread-request-timeout",
|
||||
"execution_state": "unknown",
|
||||
"message": "The UI operation may still complete after this timeout; restart Cutter before issuing further commands.",
|
||||
}, client_nonce, server_nonce)
|
||||
else:
|
||||
if request.get("kind") == "status" and reply.get("ok") is True:
|
||||
reply["completed_connection"] = self._completion_watermark()
|
||||
self._send_authenticated(connection, reply, client_nonce, server_nonce)
|
||||
except socket.timeout:
|
||||
if authenticated:
|
||||
self._send_authenticated(connection, {
|
||||
@@ -614,77 +820,217 @@ class _BridgeServer(threading.Thread):
|
||||
}, client_nonce, server_nonce)
|
||||
except Exception as error:
|
||||
self._send(connection, {"ok": False, "error": str(error)})
|
||||
self.server.close()
|
||||
try:
|
||||
self.descriptor.unlink(missing_ok=True)
|
||||
except OSError:
|
||||
pass
|
||||
finally:
|
||||
self._note_connection_finished(connection_ordinal)
|
||||
with self._connections_lock:
|
||||
self._connections.discard(connection)
|
||||
|
||||
def _note_connection_finished(self, ordinal: int) -> None:
|
||||
"""Record one accepted connection as terminated.
|
||||
|
||||
The watermark is the longest prefix 1..W that has terminated. A later
|
||||
status cannot report an earlier connection that is still reading or
|
||||
still waiting to run.
|
||||
"""
|
||||
with self._connections_lock:
|
||||
if ordinal <= self._finished_through or ordinal in self._finished_ordinals:
|
||||
return
|
||||
self._finished_ordinals.add(ordinal)
|
||||
while self._finished_through + 1 in self._finished_ordinals:
|
||||
self._finished_through += 1
|
||||
self._finished_ordinals.discard(self._finished_through)
|
||||
|
||||
def _completion_watermark(self) -> str:
|
||||
with self._connections_lock:
|
||||
return f"{self._finished_through:016x}"
|
||||
|
||||
@staticmethod
|
||||
def _receive_frame(connection: socket.socket) -> dict[str, Any]:
|
||||
def _receive_frame(
|
||||
connection: socket.socket,
|
||||
timeout_seconds: float = AUTH_FRAME_TIMEOUT_SECONDS,
|
||||
) -> dict[str, Any]:
|
||||
data = bytearray()
|
||||
deadline = time.monotonic() + AUTH_FRAME_TIMEOUT_SECONDS
|
||||
while b"\n" not in data:
|
||||
if len(data) >= MAX_FRAME_BYTES:
|
||||
raise ValueError("frame-limit-exceeded")
|
||||
deadline = time.monotonic() + timeout_seconds
|
||||
newline = -1
|
||||
while newline < 0:
|
||||
if len(data) > MAX_FRAME_BYTES:
|
||||
raise _frame_limit_exceeded()
|
||||
remaining = deadline - time.monotonic()
|
||||
if remaining <= 0:
|
||||
raise socket.timeout("authentication frame timed out")
|
||||
connection.settimeout(remaining)
|
||||
# MAX_FRAME_BYTES limits the JSON payload; the terminating LF is
|
||||
# framing and may be the one byte beyond that payload budget.
|
||||
part = connection.recv(min(65536, MAX_FRAME_BYTES + 1 - len(data)))
|
||||
if not part:
|
||||
raise ValueError("incomplete authentication frame")
|
||||
scanned = len(data)
|
||||
data.extend(part)
|
||||
line, remainder = bytes(data).split(b"\n", 1)
|
||||
if len(line) > MAX_FRAME_BYTES or remainder:
|
||||
# The delimiter is one byte, so it cannot straddle a chunk.
|
||||
# Search only the bytes just received.
|
||||
newline = data.find(b"\n", scanned)
|
||||
if newline > MAX_FRAME_BYTES:
|
||||
raise _frame_limit_exceeded()
|
||||
if newline != len(data) - 1:
|
||||
raise ValueError("invalid framed request")
|
||||
value = json.loads(line)
|
||||
value = json.loads(bytes(data[:newline]))
|
||||
return value if isinstance(value, dict) else {}
|
||||
|
||||
def _send_authenticated(self, connection: socket.socket, value: dict[str, Any], client_nonce: str, server_nonce: str) -> None:
|
||||
encoded = self._encode_authenticated_response(value, client_nonce, server_nonce)
|
||||
if encoded is None:
|
||||
value = self._truncated_response(value)
|
||||
encoded = self._encode_authenticated_response(value, client_nonce, server_nonce)
|
||||
if encoded is None:
|
||||
# This fixed-size fallback is checked through the same signed framing path.
|
||||
value = {
|
||||
"ok": False,
|
||||
"error": "response-limit-exceeded",
|
||||
"execution_state": value.get("execution_state", "unknown"),
|
||||
"output": None,
|
||||
"output_truncated": True,
|
||||
"message": "The result exceeded the bridge frame limit; command completion state is preserved.",
|
||||
}
|
||||
encoded = self._encode_authenticated_response(value, client_nonce, server_nonce)
|
||||
if encoded is None:
|
||||
if self._deliver_authenticated(connection, value, client_nonce, server_nonce):
|
||||
return
|
||||
try:
|
||||
connection.sendall(encoded)
|
||||
except OSError:
|
||||
pass
|
||||
# Keep the recovery payload. Include the observed path when it
|
||||
# fits. An explicit null path means unknown, so the client does
|
||||
# not pair this generation with the descriptor's older path.
|
||||
bounded = self._bounded_status_response(value)
|
||||
if bounded is not None:
|
||||
observed_path = value.get("current_file")
|
||||
if isinstance(observed_path, str) and observed_path:
|
||||
with_path = dict(bounded)
|
||||
with_path["current_file"] = observed_path
|
||||
with_path.pop("message", None)
|
||||
if self._deliver_authenticated(
|
||||
connection, with_path, client_nonce, server_nonce
|
||||
):
|
||||
return
|
||||
if self._deliver_authenticated(
|
||||
connection, bounded, client_nonce, server_nonce
|
||||
):
|
||||
return
|
||||
command = self._bounded_command_response(value)
|
||||
if command is not None:
|
||||
observed_path = value.get("current_file")
|
||||
if isinstance(observed_path, str) and observed_path:
|
||||
with_path = dict(command)
|
||||
with_path["current_file"] = observed_path
|
||||
with_path.pop("message", None)
|
||||
if self._deliver_authenticated(
|
||||
connection, with_path, client_nonce, server_nonce
|
||||
):
|
||||
return
|
||||
if self._deliver_authenticated(
|
||||
connection, command, client_nonce, server_nonce
|
||||
):
|
||||
return
|
||||
value = self._truncated_response(value)
|
||||
if self._deliver_authenticated(connection, value, client_nonce, server_nonce):
|
||||
return
|
||||
# This fixed-size fallback is checked through the same signed framing path.
|
||||
self._deliver_authenticated(connection, {
|
||||
"ok": False,
|
||||
"error": "response-limit-exceeded",
|
||||
"execution_state": value.get("execution_state", "unknown"),
|
||||
"output": None,
|
||||
"output_truncated": True,
|
||||
"message": "The result exceeded the bridge frame limit; command completion state is preserved.",
|
||||
}, client_nonce, server_nonce)
|
||||
|
||||
def _encode_authenticated_response(self, value: dict[str, Any], client_nonce: str, server_nonce: str) -> bytes | None:
|
||||
def _deliver_authenticated(
|
||||
self, connection: socket.socket, value: dict[str, Any], client_nonce: str, server_nonce: str
|
||||
) -> bool:
|
||||
proof = self._authenticated_proof(value, client_nonce, server_nonce)
|
||||
if proof is None:
|
||||
return False
|
||||
try:
|
||||
self._write_authenticated_frame(connection, value, proof)
|
||||
except OSError:
|
||||
# A disconnected caller must not fall through to another payload.
|
||||
pass
|
||||
return True
|
||||
|
||||
def _authenticated_proof(
|
||||
self, value: dict[str, Any], client_nonce: str, server_nonce: str
|
||||
) -> str | None:
|
||||
if not _within_response_limit(value):
|
||||
return None
|
||||
prefix = b'{"response":"'
|
||||
suffix = b'","proof":"' + (b"0" * 64) + b'"}\n'
|
||||
frame_size = len(prefix) + len(suffix)
|
||||
response_parts: list[bytes] = []
|
||||
escaped_parts: list[bytes] = []
|
||||
for fragment in json.JSONEncoder(ensure_ascii=False, separators=(",", ":")).iterencode(value):
|
||||
raw = fragment.encode("utf-8")
|
||||
escaped = json.dumps(fragment, ensure_ascii=False)[1:-1].encode("utf-8")
|
||||
frame_size += len(escaped)
|
||||
# The payload budget excludes the terminating LF. Fragments are
|
||||
# measured and signed here, then discarded. The write pass encodes
|
||||
# them again so a maximum-sized reply is not held in several copies.
|
||||
frame_size = _AUTHENTICATED_FRAME_OVERHEAD
|
||||
proof = hmac.new(self.token.encode(), digestmod=hashlib.sha256)
|
||||
proof.update(
|
||||
f"rea-cutter-response-v2:{self.session_id}:{client_nonce}:{server_nonce}:".encode()
|
||||
)
|
||||
for fragment in _response_fragments(value):
|
||||
frame_size += len(_escape_json_fragment(fragment))
|
||||
if frame_size > MAX_FRAME_BYTES:
|
||||
return None
|
||||
response_parts.append(raw)
|
||||
escaped_parts.append(escaped)
|
||||
proof = hmac.new(self.token.encode(), digestmod=hashlib.sha256)
|
||||
proof.update(f"rea-cutter-response-v2:{self.session_id}:{client_nonce}:{server_nonce}:".encode())
|
||||
for part in response_parts:
|
||||
proof.update(part)
|
||||
return prefix + b"".join(escaped_parts) + b'","proof":"' + proof.hexdigest().encode() + b'"}\n'
|
||||
proof.update(fragment.encode("utf-8"))
|
||||
return proof.hexdigest()
|
||||
|
||||
def _encode_authenticated_response(
|
||||
self, value: dict[str, Any], client_nonce: str, server_nonce: str
|
||||
) -> bytes | None:
|
||||
"""Return one exact frame. The socket path writes the same pieces."""
|
||||
proof = self._authenticated_proof(value, client_nonce, server_nonce)
|
||||
if proof is None:
|
||||
return None
|
||||
return b"".join(self._iter_authenticated_frame(value, proof))
|
||||
|
||||
def _iter_authenticated_frame(self, value: dict[str, Any], proof: str):
|
||||
yield _AUTHENTICATED_PREFIX
|
||||
for fragment in _response_fragments(value):
|
||||
yield _escape_json_fragment(fragment)
|
||||
yield _AUTHENTICATED_PROOF_MARK + proof.encode("ascii") + b'"}\n'
|
||||
|
||||
def _write_authenticated_frame(
|
||||
self, connection: socket.socket, value: dict[str, Any], proof: str
|
||||
) -> None:
|
||||
pending = bytearray()
|
||||
for chunk in self._iter_authenticated_frame(value, proof):
|
||||
pending.extend(chunk)
|
||||
if len(pending) >= _AUTHENTICATED_WRITE_BUFFER_BYTES:
|
||||
connection.sendall(pending)
|
||||
pending.clear()
|
||||
if pending:
|
||||
connection.sendall(pending)
|
||||
|
||||
@staticmethod
|
||||
def _bounded_status_response(value: dict[str, Any]) -> dict[str, Any] | None:
|
||||
if "completed_commands" not in value and "completed_connection" not in value:
|
||||
return None
|
||||
bounded: dict[str, Any] = {
|
||||
"ok": value.get("ok") is True,
|
||||
"session_id": value.get("session_id"),
|
||||
"document_generation": value.get("document_generation"),
|
||||
"identity_status": value.get("identity_status", "partial"),
|
||||
"completed_commands": value.get("completed_commands"),
|
||||
"current_file": None,
|
||||
"message": (
|
||||
"current_file is unknown because the status frame exceeded "
|
||||
"REA_BRIDGE_MAX_REQUEST_BYTES. Do not reuse an older descriptor "
|
||||
"path with this document_generation."
|
||||
),
|
||||
}
|
||||
if "completed_connection" in value:
|
||||
bounded["completed_connection"] = value["completed_connection"]
|
||||
return bounded
|
||||
|
||||
@staticmethod
|
||||
def _bounded_command_response(value: dict[str, Any]) -> dict[str, Any] | None:
|
||||
if "execution_state" not in value and "document_generation" not in value:
|
||||
return None
|
||||
bounded: dict[str, Any] = {
|
||||
"ok": value.get("ok") is True,
|
||||
"output": None,
|
||||
"execution_state": value.get("execution_state", "unknown"),
|
||||
"output_truncated": True,
|
||||
"current_file": None,
|
||||
"message": (
|
||||
"current_file is unknown because the result frame exceeded "
|
||||
"REA_BRIDGE_MAX_REQUEST_BYTES. The command completion state and "
|
||||
"document_generation are preserved. Do not reuse an older "
|
||||
"descriptor path with this document_generation."
|
||||
),
|
||||
}
|
||||
generation = value.get("document_generation")
|
||||
if isinstance(generation, int) and not isinstance(generation, bool):
|
||||
bounded["document_generation"] = generation
|
||||
if value.get("identity_status") == "partial":
|
||||
bounded["identity_status"] = "partial"
|
||||
if value.get("ok") is not True and isinstance(value.get("error"), str):
|
||||
bounded["error"] = value["error"]
|
||||
return bounded
|
||||
|
||||
@staticmethod
|
||||
def _truncated_response(value: dict[str, Any]) -> dict[str, Any]:
|
||||
@@ -742,6 +1088,17 @@ class _BridgeServer(threading.Thread):
|
||||
self.server.close()
|
||||
except OSError:
|
||||
pass
|
||||
with self._connections_lock:
|
||||
connections = list(self._connections)
|
||||
for connection in connections:
|
||||
try:
|
||||
connection.shutdown(socket.SHUT_RDWR)
|
||||
except OSError:
|
||||
pass
|
||||
try:
|
||||
connection.close()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
class ReaCutterPlugin(cutter.CutterPlugin):
|
||||
@@ -775,6 +1132,128 @@ def create_cutter_plugin() -> ReaCutterPlugin:
|
||||
return ReaCutterPlugin()
|
||||
|
||||
|
||||
def _json_object_key(key: Any) -> str:
|
||||
"""Match CPython's JSON object-key text before quoting."""
|
||||
if isinstance(key, str):
|
||||
return key
|
||||
if key is True:
|
||||
return "true"
|
||||
if key is False:
|
||||
return "false"
|
||||
if key is None:
|
||||
return "null"
|
||||
if isinstance(key, int):
|
||||
return str(key)
|
||||
if isinstance(key, float):
|
||||
return json.dumps(key, separators=(",", ":"))
|
||||
raise TypeError("keys must be str, int, float, bool or None")
|
||||
|
||||
|
||||
def _response_fragments(value: Any):
|
||||
"""Yield compact JSON pieces whose concatenation is the encoded value.
|
||||
|
||||
String contents are sliced before encoding so a large output never becomes
|
||||
one frame-sized fragment. Each piece is at most ``_JSON_CHUNK_CHARS``
|
||||
characters, or the six-byte ``\\u00XX`` expansion of one such slice.
|
||||
"""
|
||||
if isinstance(value, str):
|
||||
yield '"'
|
||||
for start in range(0, len(value), _JSON_CHUNK_CHARS):
|
||||
yield json.dumps(
|
||||
value[start:start + _JSON_CHUNK_CHARS], ensure_ascii=False
|
||||
)[1:-1]
|
||||
yield '"'
|
||||
return
|
||||
if isinstance(value, dict):
|
||||
yield "{"
|
||||
first = True
|
||||
for key, item in value.items():
|
||||
if not first:
|
||||
yield ","
|
||||
first = False
|
||||
yield from _response_fragments(_json_object_key(key))
|
||||
yield ":"
|
||||
yield from _response_fragments(item)
|
||||
yield "}"
|
||||
return
|
||||
if isinstance(value, (list, tuple)):
|
||||
yield from _list_fragments(value)
|
||||
return
|
||||
token = _scalar_token(value)
|
||||
if token is None:
|
||||
raise TypeError("response value is not JSON")
|
||||
yield token
|
||||
|
||||
|
||||
def _scalar_token(value: Any) -> str | None:
|
||||
"""Compact JSON for one scalar. None means the value needs structure."""
|
||||
if type(value) is int:
|
||||
return str(value)
|
||||
if value is None:
|
||||
return "null"
|
||||
if value is True:
|
||||
return "true"
|
||||
if value is False:
|
||||
return "false"
|
||||
if isinstance(value, float):
|
||||
return json.dumps(value, separators=(",", ":"))
|
||||
return None
|
||||
|
||||
|
||||
def _list_fragments(value: list[Any] | tuple[Any, ...]):
|
||||
"""Encode a list, batching scalars into bounded pieces.
|
||||
|
||||
One ``json.dumps`` per number makes a dense array miss the client
|
||||
deadline. A batch is at most ``_JSON_CHUNK_CHARS`` of compact JSON.
|
||||
"""
|
||||
yield "["
|
||||
first = True
|
||||
batch: list[str] = []
|
||||
batch_len = 0
|
||||
|
||||
def flush_batch() -> str | None:
|
||||
nonlocal first, batch, batch_len
|
||||
if not batch:
|
||||
return None
|
||||
piece = ",".join(batch)
|
||||
batch = []
|
||||
batch_len = 0
|
||||
if first:
|
||||
first = False
|
||||
return piece
|
||||
return "," + piece
|
||||
|
||||
for item in value:
|
||||
token = _scalar_token(item)
|
||||
if token is None:
|
||||
emitted = flush_batch()
|
||||
if emitted is not None:
|
||||
yield emitted
|
||||
if first:
|
||||
first = False
|
||||
else:
|
||||
yield ","
|
||||
yield from _response_fragments(item)
|
||||
continue
|
||||
extra = len(token) if not batch else len(token) + 1
|
||||
if batch and batch_len + extra > _JSON_CHUNK_CHARS:
|
||||
emitted = flush_batch()
|
||||
if emitted is not None:
|
||||
yield emitted
|
||||
extra = len(token)
|
||||
batch.append(token)
|
||||
batch_len += extra
|
||||
emitted = flush_batch()
|
||||
if emitted is not None:
|
||||
yield emitted
|
||||
yield "]"
|
||||
|
||||
|
||||
def _escape_json_fragment(fragment: str) -> bytes:
|
||||
"""Escape one raw JSON piece for the outer response string."""
|
||||
return json.dumps(fragment, ensure_ascii=False)[1:-1].encode("utf-8")
|
||||
|
||||
|
||||
def _within_response_limit(value: Any) -> bool:
|
||||
pending = [value]
|
||||
seen: set[int] = set()
|
||||
@@ -798,13 +1277,22 @@ def _within_response_limit(value: Any) -> bool:
|
||||
# Unencodable output also needs the signed omission fallback.
|
||||
return False
|
||||
size += current.count('"') + current.count("\\")
|
||||
size += sum(5 for character in current if ord(character) < 0x20)
|
||||
# A short escape is two JSON bytes and was already counted as one.
|
||||
# Other controls expand to a six-byte \\u00XX sequence.
|
||||
size += sum(
|
||||
1 if ord(character) in (0x08, 0x09, 0x0A, 0x0C, 0x0D) else 5
|
||||
for character in current
|
||||
if ord(character) < 0x20
|
||||
)
|
||||
elif isinstance(current, dict):
|
||||
identity = id(current)
|
||||
if identity in seen:
|
||||
return False
|
||||
seen.add(identity)
|
||||
size += 2 + 4 * len(current)
|
||||
count = len(current)
|
||||
# Braces, one colon per entry, and commas between entries.
|
||||
# Keys and values are counted when they are visited.
|
||||
size += 2 + count + max(0, count - 1)
|
||||
if size > MAX_FRAME_BYTES:
|
||||
return False
|
||||
pending.extend(current.keys())
|
||||
@@ -814,12 +1302,29 @@ def _within_response_limit(value: Any) -> bool:
|
||||
if identity in seen:
|
||||
return False
|
||||
seen.add(identity)
|
||||
size += 2 + 2 * len(current)
|
||||
count = len(current)
|
||||
# Brackets and commas between items. Each item is counted below.
|
||||
size += 2 + max(0, count - 1)
|
||||
if size > MAX_FRAME_BYTES:
|
||||
return False
|
||||
pending.extend(current)
|
||||
elif current is None:
|
||||
size += 4
|
||||
elif current is True:
|
||||
size += 4
|
||||
elif current is False:
|
||||
size += 5
|
||||
elif isinstance(current, int):
|
||||
size += len(str(current))
|
||||
elif isinstance(current, float):
|
||||
size += len(json.dumps(current, separators=(",", ":")))
|
||||
else:
|
||||
size += 16
|
||||
try:
|
||||
size += len(
|
||||
json.dumps(current, ensure_ascii=False, separators=(",", ":"))
|
||||
)
|
||||
except (TypeError, ValueError):
|
||||
return False
|
||||
if size > MAX_FRAME_BYTES:
|
||||
return False
|
||||
return True
|
||||
@@ -1,38 +1,91 @@
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||
import ghidra.app.services.Analyzer;
|
||||
import ghidra.app.util.headless.HeadlessScript;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
|
||||
/** Disable the named auto-analyzers before default auto-analysis. */
|
||||
/**
|
||||
* Disable the named auto-analyzers before default auto-analysis.
|
||||
*
|
||||
* REA_GHIDRA_DISABLED_ANALYZERS is process-wide, but Ghidra registers only the
|
||||
* installed analyzers whose canAnalyze(program) accepts this program. A name an
|
||||
* installed analyzer provides without being registered here is not applicable
|
||||
* and is recorded instead of rejected; a name no installed analyzer provides
|
||||
* aborts the import. The outcome is stored as a program property that the
|
||||
* bridge reports during its handshake.
|
||||
*/
|
||||
public final class ReaGhidraAnalysisOptions extends HeadlessScript {
|
||||
static final String REPORT_OPTION = "REA disabled analyzers";
|
||||
private static final String SETTING = "REA_GHIDRA_DISABLED_ANALYZERS";
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
String[] arguments = getScriptArgs();
|
||||
if (arguments.length != 1 || arguments[0].isBlank()) {
|
||||
throw new IllegalArgumentException(
|
||||
"ReaGhidraAnalysisOptions requires one comma-separated analyzer-name argument");
|
||||
"ReaGhidraAnalysisOptions requires one comma-separated " + SETTING + " argument");
|
||||
}
|
||||
String[] names = arguments[0].split(",");
|
||||
boolean[] registered = new boolean[names.length];
|
||||
AutoAnalysisManager analysis = AutoAnalysisManager.getAnalysisManager(currentProgram);
|
||||
Map<String, String> options = getCurrentAnalysisOptionsAndValues(currentProgram);
|
||||
for (String requestedName : names) {
|
||||
Set<String> installed = null;
|
||||
for (int index = 0; index < names.length; index++) {
|
||||
monitor.checkCancelled();
|
||||
String name = requestedName.trim();
|
||||
if (analysis.getAnalyzer(name) == null || !options.containsKey(name)) {
|
||||
throw new IllegalArgumentException("Unknown Ghidra analyzer for this program: " + name);
|
||||
String name = names[index].trim();
|
||||
names[index] = name;
|
||||
if (analysis.getAnalyzer(name) != null) {
|
||||
if (!options.containsKey(name)) {
|
||||
throw new IllegalStateException(SETTING + " names " + name +
|
||||
", which Ghidra registered for this program without an enablement option");
|
||||
}
|
||||
registered[index] = true;
|
||||
continue;
|
||||
}
|
||||
if (installed == null) installed = installedAnalyzerNames();
|
||||
if (!installed.contains(name)) {
|
||||
throw new IllegalArgumentException(SETTING + " names " + name +
|
||||
", which is not an analyzer in this Ghidra installation");
|
||||
}
|
||||
}
|
||||
for (String requestedName : names) {
|
||||
for (int index = 0; index < names.length; index++) {
|
||||
monitor.checkCancelled();
|
||||
setAnalysisOption(currentProgram, requestedName.trim(), "false");
|
||||
if (registered[index]) setAnalysisOption(currentProgram, names[index], "false");
|
||||
}
|
||||
options = getCurrentAnalysisOptionsAndValues(currentProgram);
|
||||
for (String requestedName : names) {
|
||||
JsonArray analyzers = new JsonArray();
|
||||
for (int index = 0; index < names.length; index++) {
|
||||
monitor.checkCancelled();
|
||||
String name = requestedName.trim();
|
||||
if (!"false".equals(options.get(name))) {
|
||||
throw new IllegalStateException("Ghidra analyzer remained enabled: " + name);
|
||||
String name = names[index];
|
||||
if (registered[index] && !"false".equals(options.get(name))) {
|
||||
throw new IllegalStateException(SETTING + " names " + name +
|
||||
", which remained enabled for this program");
|
||||
}
|
||||
JsonObject analyzer = new JsonObject();
|
||||
analyzer.addProperty("name", name);
|
||||
analyzer.addProperty("status", registered[index] ? "disabled" : "not_applicable");
|
||||
analyzers.add(analyzer);
|
||||
}
|
||||
JsonObject report = new JsonObject();
|
||||
report.addProperty("format", "rea-ghidra-disabled-analyzers-v1");
|
||||
report.add("analyzers", analyzers);
|
||||
currentProgram.getOptions(Program.PROGRAM_INFO).setString(REPORT_OPTION, report.toString());
|
||||
println("REA disabled analyzers: " + report);
|
||||
}
|
||||
|
||||
/** The same analyzer universe AutoAnalysisManager filters by canAnalyze(program). */
|
||||
private static Set<String> installedAnalyzerNames() {
|
||||
Set<String> names = new HashSet<>();
|
||||
for (Analyzer analyzer : ClassSearcher.getInstances(Analyzer.class)) {
|
||||
names.add(analyzer.getName());
|
||||
}
|
||||
return names;
|
||||
}
|
||||
}
|
||||
@@ -523,6 +523,11 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
String seeds = currentProgram.getOptions(ghidra.program.model.listing.Program.PROGRAM_INFO)
|
||||
.getString("REA analysis seeds", null);
|
||||
if (seeds != null) result.add("analysis_seeds", JsonParser.parseString(seeds));
|
||||
// Written by ReaGhidraAnalysisOptions before auto-analysis; REA checks it
|
||||
// against the committed profile.
|
||||
String disabledAnalyzers = currentProgram.getOptions(ghidra.program.model.listing.Program.PROGRAM_INFO)
|
||||
.getString("REA disabled analyzers", null);
|
||||
if (disabledAnalyzers != null) result.add("disabled_analyzers", JsonParser.parseString(disabledAnalyzers));
|
||||
// Written by ReaGhidraMipsSoftFloat after analysis; REA requires it
|
||||
// exactly when the committed profile declares soft-float storage.
|
||||
String softFloat = currentProgram.getOptions(ghidra.program.model.listing.Program.PROGRAM_INFO)
|
||||
@@ -1263,9 +1268,11 @@ public final class ReaGhidraBridge extends HeadlessScript {
|
||||
result.add("procedure", function == null ? JsonNull.INSTANCE : GSON.toJsonTree(canonicalAddress(function.getEntryPoint())));
|
||||
result.addProperty("architecture", currentProgram.getLanguageID().getIdAsString());
|
||||
result.addProperty("mode", currentProgram.getLanguage().getLanguageDescription().getVariant());
|
||||
if (currentProgram.getLanguageID().getIdAsString().startsWith("MIPS:")) {
|
||||
if (currentProgram.getLanguageID().getIdAsString().startsWith("MIPS:") ||
|
||||
currentProgram.getLanguageID().getIdAsString().startsWith("ARM:")) {
|
||||
JsonArray decoderContext = new JsonArray();
|
||||
var modeRegister = currentProgram.getRegister("ISA_MODE");
|
||||
String regName = currentProgram.getLanguageID().getIdAsString().startsWith("MIPS:") ? "ISA_MODE" : "TMode";
|
||||
var modeRegister = currentProgram.getRegister(regName);
|
||||
if (modeRegister != null) {
|
||||
var modeValue = currentProgram.getProgramContext().getValue(modeRegister, address, false);
|
||||
JsonObject context = new JsonObject();
|
||||
|
||||
+104
-1
@@ -8,12 +8,100 @@ API access on this thread: moving dispatch to a worker can deadlock Hopper.
|
||||
import json
|
||||
import hmac
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
from typing import Any, Optional, Protocol, Sequence
|
||||
|
||||
BAD_ADDRESSES = (-1, 0xFFFFFFFFFFFFFFFF, None)
|
||||
# The native label setter truncates NSString names at this UTF-16 extent.
|
||||
HOPPER_SYMBOL_NAME_UTF16_UNITS = 1024
|
||||
# Request JSON payload budget in bytes, excluding the trailing LF.
|
||||
# REA_BRIDGE_MAX_REQUEST_BYTES selects it. Unset stays 16777216.
|
||||
# 7464 is the authenticated Cutter frame of the largest bounded symbol name.
|
||||
# Cutter's 64-receipt recovery status is smaller with a null path. A path
|
||||
# that does not fit is null, not an older descriptor path.
|
||||
# 536870887 is Node's 536870888-character string ceiling minus the framing LF.
|
||||
# The ceiling is the encoded payload; JSON expansion is measured before it.
|
||||
_BRIDGE_MAX_REQUEST_BYTES_SETTING = "REA_BRIDGE_MAX_REQUEST_BYTES"
|
||||
DEFAULT_BRIDGE_MAX_REQUEST_BYTES = 16 * 1024 * 1024
|
||||
MINIMUM_BRIDGE_MAX_REQUEST_BYTES = 7464
|
||||
MAXIMUM_BRIDGE_MAX_REQUEST_BYTES = 536870887
|
||||
|
||||
|
||||
def _bridge_max_request_bytes_constraint():
|
||||
return (
|
||||
"REA_BRIDGE_MAX_REQUEST_BYTES must be a positive decimal integer "
|
||||
"from %d to %d bytes; the default is %d bytes (16 MiB). "
|
||||
"A value below %d bytes cannot carry the largest admitted "
|
||||
"symbol-name command, and a larger value is refused so the encoded "
|
||||
"payload plus its framing LF stays one string under Node's "
|
||||
"single-string ceiling."
|
||||
% (
|
||||
MINIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
MAXIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
DEFAULT_BRIDGE_MAX_REQUEST_BYTES,
|
||||
MINIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _parse_bridge_max_request_bytes(raw):
|
||||
"""Refuse a non-decimal or out-of-range ceiling. Never fall back."""
|
||||
constraint = _bridge_max_request_bytes_constraint()
|
||||
if isinstance(raw, bool):
|
||||
raise RuntimeError(constraint)
|
||||
if isinstance(raw, int):
|
||||
value = raw
|
||||
elif isinstance(raw, str):
|
||||
# ASCII digits only. str.isdigit() accepts numerals such as U+0668
|
||||
# that the TypeScript setting rejects.
|
||||
if re.fullmatch(r"[1-9][0-9]*", raw) is None:
|
||||
raise RuntimeError(constraint)
|
||||
value = int(raw)
|
||||
else:
|
||||
raise RuntimeError(constraint)
|
||||
if (
|
||||
value < MINIMUM_BRIDGE_MAX_REQUEST_BYTES
|
||||
or value > MAXIMUM_BRIDGE_MAX_REQUEST_BYTES
|
||||
):
|
||||
raise RuntimeError(constraint)
|
||||
return value
|
||||
|
||||
|
||||
def _resolve_bridge_max_request_bytes():
|
||||
"""Prefer the bootstrap injection, then the process environment, then 16 MiB."""
|
||||
injected = globals().get(_BRIDGE_MAX_REQUEST_BYTES_SETTING)
|
||||
if injected is not None:
|
||||
return _parse_bridge_max_request_bytes(injected), "setting"
|
||||
raw = os.environ.get(_BRIDGE_MAX_REQUEST_BYTES_SETTING)
|
||||
if raw is None:
|
||||
return DEFAULT_BRIDGE_MAX_REQUEST_BYTES, "default"
|
||||
return _parse_bridge_max_request_bytes(raw), "setting"
|
||||
|
||||
|
||||
MAX_REQUEST_BYTES, BRIDGE_MAX_REQUEST_BYTES_SOURCE = (
|
||||
_resolve_bridge_max_request_bytes()
|
||||
)
|
||||
|
||||
|
||||
def _bridge_max_request_bytes_recovery():
|
||||
return (
|
||||
"The effective REA_BRIDGE_MAX_REQUEST_BYTES value is %d bytes "
|
||||
"(source %s; default %d, floor %d, maximum %d). "
|
||||
"Set REA_BRIDGE_MAX_REQUEST_BYTES in the environment that starts REA "
|
||||
"to a decimal integer from %d to %d, then restart REA. "
|
||||
"Restart Hopper or Cutter from that same environment so the bridge "
|
||||
"uses this ceiling."
|
||||
% (
|
||||
MAX_REQUEST_BYTES,
|
||||
BRIDGE_MAX_REQUEST_BYTES_SOURCE,
|
||||
DEFAULT_BRIDGE_MAX_REQUEST_BYTES,
|
||||
MINIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
MAXIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
MINIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
MAXIMUM_BRIDGE_MAX_REQUEST_BYTES,
|
||||
)
|
||||
)
|
||||
_rea_session_document = None
|
||||
_search_inventory_cache = {}
|
||||
_pseudocode_cache = {}
|
||||
@@ -740,6 +828,7 @@ def _dispatch(method, params):
|
||||
"version": "1.0.0",
|
||||
"run_id": REA_RUN_ID,
|
||||
"process_id": os.getpid(),
|
||||
"max_request_bytes": MAX_REQUEST_BYTES,
|
||||
}
|
||||
if method in ("shutdown", "shutdown_document"):
|
||||
document = _session_document()
|
||||
@@ -1060,9 +1149,23 @@ def _serve_connection(connection):
|
||||
should_stop = False
|
||||
try:
|
||||
while True:
|
||||
line = file.readline()
|
||||
# Bound the read itself. The payload budget excludes LF, so permit
|
||||
# one additional byte for the delimiter while still refusing an
|
||||
# oversized unterminated peer without waiting for EOF.
|
||||
line = file.readline(MAX_REQUEST_BYTES + 1)
|
||||
if not line:
|
||||
break
|
||||
if not line.endswith(b"\n"):
|
||||
message = (
|
||||
"Bridge request exceeds the %d-byte payload limit. %s"
|
||||
% (MAX_REQUEST_BYTES, _bridge_max_request_bytes_recovery())
|
||||
if len(line) > MAX_REQUEST_BYTES
|
||||
else "Incomplete bridge request frame"
|
||||
)
|
||||
_write_message(file, {"id": 0, "error": _safe_diagnostic(
|
||||
InvalidRequestError(message)
|
||||
)})
|
||||
break
|
||||
request_id = None
|
||||
authenticated = False
|
||||
should_stop = False
|
||||
|
||||
@@ -32,6 +32,10 @@ export default defineConfig({
|
||||
{ text: "IL2CPP metadata", link: "/il2cpp-metadata" },
|
||||
{ text: "Model artifacts", link: "/model-artifacts" },
|
||||
{ text: "Rust dependencies", link: "/rust-binaries" },
|
||||
{ text: "PE certificates", link: "/pe-certificates" },
|
||||
{ text: "ELF notes", link: "/elf-notes" },
|
||||
{ text: "CPython pyc files", link: "/python-pyc" },
|
||||
{ text: "Erlang BEAM", link: "/erlang-beam" },
|
||||
{
|
||||
text: "JavaScript and Electron",
|
||||
link: "/javascript-artifact-reconstruction",
|
||||
@@ -83,6 +87,10 @@ export default defineConfig({
|
||||
items: [
|
||||
{ text: "MCP contracts", link: "/mcp-contracts" },
|
||||
{ text: "Tool design", link: "/tool-design" },
|
||||
{
|
||||
text: "Admission limits and recovery",
|
||||
link: "/design/limits-and-recovery",
|
||||
},
|
||||
{ text: "Testing", link: "/testing" },
|
||||
{ text: "Client verification", link: "/client-verification" },
|
||||
{
|
||||
|
||||
@@ -90,7 +90,7 @@ existing analysis families directly, for example
|
||||
| `read_adb_logcat` | read | Bounded `logcat -d -t` dump for one buffer, optional pid filter |
|
||||
| `list_adb_packages` | read | `pm list packages -f` with scope; base APK device paths |
|
||||
| `resolve_adb_packages` | read | Case-insensitive package-name substring search with exact-match flag |
|
||||
| `inspect_adb_package` | read | `dumpsys package` projection: versions, install times, installer, flags, permission count |
|
||||
| `inspect_adb_package` | read | `dumpsys package` projection: versions, install times, installer, flags, and count of listed requested-permission rows (including Unicode names) |
|
||||
| `list_adb_directory` | read | NUL-framed immediate children, including hidden entries: kinds, permissions, owner, group, sizes, symlink targets |
|
||||
| `pull_adb_package` | read | Complete split APK set from `pm path`, each file digested |
|
||||
| `pull_adb_file` | read | One absolute device path pulled and digested |
|
||||
@@ -103,6 +103,11 @@ existing analysis families directly, for example
|
||||
| `start_adb_activity` | **mutates device** | Starts an intent (`am start -a` with optional URI, component, and up to 16 typed extras); preserves the activity manager's verdict |
|
||||
| `stop_adb_app` | **mutates device** | Force-stops every process of a package, ending a dynamic-analysis run |
|
||||
|
||||
When `push_adb_file` receives an existing directory, adb places the local file
|
||||
inside it under the local basename; Evidence reports that effective file path
|
||||
while retaining the caller's directory path in the input parameters. The
|
||||
private read-only staging copy preserves the source file's executable bits.
|
||||
|
||||
For `inspect_adb_window`, `focus_contexts` retains each display header, its exact
|
||||
display ID when recognized, and every focus declaration with its original line.
|
||||
Declarations without a display header are explicitly `unscoped`. A missing
|
||||
@@ -136,8 +141,10 @@ and during shutdown.
|
||||
labelled hex in `unparsed_lines` and make directory coverage partial.
|
||||
- **Inferences carry their basis.** Device `kind` reports
|
||||
`kind_basis` (serial prefix or USB transport); APK `role` reports
|
||||
`role_basis: file_name`; `emulator_observed` is the build's own
|
||||
`ro.kernel.qemu` value, `null` when absent.
|
||||
`role_basis: file_name`; `emulator_observed` is derived from the build's
|
||||
`ro.kernel.qemu` property: `true` only when its value is `"1"`, `false` for
|
||||
any other reported value, and `null` when the property is absent. The raw
|
||||
property value remains available in `properties`.
|
||||
- **Device paths are not host paths.** `base_apk_device_path` values live on
|
||||
the device filesystem. Only pulls and captures produce host-local paths,
|
||||
each paired with byte size and SHA-256 digest. A pulled file's host name is
|
||||
|
||||
+238
-53
@@ -5,7 +5,8 @@ environment: an MCP server whose tools answer from what one retained web
|
||||
network capture observed, plus the environment card the agentenv framework
|
||||
reads to discover it. By default the server derives the
|
||||
[state the capture observed](#the-state-a-capture-observed) at startup and
|
||||
answers read tools from it; `--replay-only` replays the capture's records
|
||||
answers read tools from it, and the write tools whose effect the capture
|
||||
confirmed by changing it; `--replay-only` replays the capture's records
|
||||
instead. Nothing is fetched from the recorded application; every answer comes
|
||||
from retained Evidence. `rea environment-export` writes the same pair as a
|
||||
bundle folder `agent-env run` builds and runs; see
|
||||
@@ -164,7 +165,10 @@ Each such MCP tool call selects one of the records its manifest tool cites and
|
||||
returns that record's recorded response. Selection compares the supplied path
|
||||
parameters against the record's path segments at the parameter indexes, then
|
||||
the supplied query values against the record's query string, and keeps the
|
||||
record with the most matches; ties keep manifest order. The result reports
|
||||
record with the most matches; ties keep manifest order. A query argument accepts
|
||||
one string or an array of strings for repeated values; the array is matched
|
||||
against every occurrence in captured order. The raw recorded query remains the
|
||||
replay evidence. The result reports
|
||||
where the answer came from:
|
||||
|
||||
```json
|
||||
@@ -186,9 +190,14 @@ where the answer came from:
|
||||
}
|
||||
```
|
||||
|
||||
`exact_match` is true when every supplied path parameter and query value
|
||||
equals the recorded one; it says nothing about parameters the caller omitted.
|
||||
Recorded query parsing runs only when supplied query arguments affect selection.
|
||||
`exact_match` is true when every supplied path parameter and query occurrence
|
||||
matches the recorded one; it says nothing about parameters the caller omitted.
|
||||
Comparison probes retain the raw query spelling and its decoded parameter pairs
|
||||
in request order, including the interleaving of repeated values across names.
|
||||
Standalone tool calls express repeated values as per-name arrays; when matching
|
||||
records differ only in cross-name order, `exact_match` is false because those arguments cannot
|
||||
identify that order. Recorded query parsing runs only when supplied query
|
||||
arguments affect selection.
|
||||
A path value matches a recorded segment as written or after percent-decoding;
|
||||
when both kinds of match are available, the record whose segment equals the
|
||||
value as written is chosen. `recorded_query` keeps the `?` of an explicit empty
|
||||
@@ -206,7 +215,11 @@ text with `truncated: true`. `body_recorded` is false when the capture kept the
|
||||
response's status and content type but no body; `body` is then `null`, which
|
||||
is not a recorded JSON `null`. `body_encoding` is `base64` when the capture
|
||||
retained response bytes that are not valid UTF-8; `body` is then exactly those
|
||||
bytes in base64, never a lossy decoding. A retained base64 body is decoded only as far as the 256 KiB a reply can carry, and a leading byte-order mark is kept. For a `base64` body the limit applies to the recorded bytes, not their longer base64 spelling, and a cut keeps whole base64 groups. Request bodies passed to `POST`, `PUT` and `PATCH`
|
||||
bytes in base64, never a lossy decoding. An unsupported declared HAR encoding
|
||||
returns `body: null`, `body_recorded: true` and `body_encoding: "unsupported"`;
|
||||
the original encoding and encoded text remain in the cited capture Evidence.
|
||||
Such bodies supply no decoded JSON facts to state extraction.
|
||||
A retained base64 body is decoded only as far as the 256 KiB a reply can carry, and a leading byte-order mark is kept. For a `base64` body the limit applies to the recorded bytes, not their longer base64 spelling, and a cut keeps whole base64 groups. Request bodies passed to `POST`, `PUT` and `PATCH`
|
||||
tools are accepted and ignored: nothing is written, and no call changes what a
|
||||
later call returns. Arguments the tool's input schema does not name are
|
||||
refused by the MCP server as invalid arguments, so a misspelled parameter never
|
||||
@@ -234,11 +247,12 @@ moment of the capture recorded them. The
|
||||
[environment state](web-network-captures.md#environment-state) view extracts
|
||||
instead the data the capture's reads observed before the first related write:
|
||||
entity types with an identity field, entities with their recorded values,
|
||||
documents for written paths, and a render plan per read tool, kept only where
|
||||
it reproduces that tool's recordings from the state. It is the starting state
|
||||
an environment holds, loads and reports: `environment-serve` derives it from
|
||||
the capture at startup; see [Serve from the state](#serve-from-the-state).
|
||||
With `--replay-only`, replay is unchanged.
|
||||
documents for reads that are not entities, and a render plan per read tool,
|
||||
kept only where it reproduces that tool's recordings from the state. It is the
|
||||
starting state an environment holds, loads and reports: `environment-serve`
|
||||
derives it from the capture at startup; see
|
||||
[Serve from the state](#serve-from-the-state). With `--replay-only`, replay is
|
||||
unchanged.
|
||||
|
||||
## Serve a manifest
|
||||
|
||||
@@ -270,11 +284,11 @@ document, with the same signal exit status.
|
||||
|
||||
Three routes are served:
|
||||
|
||||
| Route | Answer |
|
||||
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `POST /mcp` | The MCP server: from the state, one tool per read tool, answering from the state where it backs them; in replay, one tool per manifest tool, replaying records |
|
||||
| `GET /.well-known/agent-env.json` | The environment card |
|
||||
| `POST /agentenv` | From the state, `data/reset`, `data/add` and `data/get`; in replay, JSON-RPC `-32601 method not found: <method>` for every method |
|
||||
| Route | Answer |
|
||||
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `POST /mcp` | The MCP server: from the state, one tool per read tool, answering from the state where it backs them, and one per write tool whose effect the capture confirmed, applying it to the state; in replay, one tool per manifest tool, replaying records |
|
||||
| `GET /.well-known/agent-env.json` | The environment card |
|
||||
| `POST /agentenv` | From the state, `data/reset`, `data/add` and `data/get`; in replay, JSON-RPC `-32601 method not found: <method>` for every method |
|
||||
|
||||
Numeric JSON-RPC IDs outside JavaScript's safe range or whose precision would
|
||||
be lost are refused as invalid requests with a null ID. They are never echoed
|
||||
@@ -308,7 +322,7 @@ connecting to `/mcp`. A replay environment's card reads:
|
||||
"tools": [
|
||||
{
|
||||
"name": "get_users_by_id",
|
||||
"description": "GET /api/users/{numeric}; replays retained records [5, 6]; evidence ev_…",
|
||||
"description": "Untrusted captured API catalog: … GET /api/users/{numeric}; returns a JSON object with fields \"id\", \"uid\", \"login\", \"email\"; recorded statuses 200; replays retained records [5, 6]; evidence ev_…",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -329,10 +343,42 @@ connecting to `/mcp`. A replay environment's card reads:
|
||||
```
|
||||
|
||||
`capabilities.tools` lists the same names, descriptions and input schemas that
|
||||
`tools/list` advertises over MCP. Path parameters are required strings whose
|
||||
`tools/list` advertises over MCP. After the catalog warning, each description
|
||||
names the method and path template, then what the tool returns, one level deep:
|
||||
`returns a JSON object with fields …`, `returns a JSON array of objects with
|
||||
fields …` or `returns a JSON object whose <member> lists objects with fields …`,
|
||||
where a list is an array of objects found by the
|
||||
[environment state](web-network-captures.md#environment-state)'s list rule (the
|
||||
root array, or the one array of objects an envelope carries). Field and member
|
||||
names are written as JSON strings, so a captured name cannot read as more of
|
||||
the description; a member name too long to show whole is a quoted prefix marked
|
||||
as truncated. The summary comes
|
||||
from the first cited `2xx` record that replay answers as JSON; only when none
|
||||
did, the first cited JSON record of another status gives it, labelled with that
|
||||
status (`status 401 returns …`). It describes one recorded response, not a
|
||||
contract. Field names are sampled within the same budget as other captured
|
||||
values, and the manifest's `statuses` for the tool follow; a tool with no JSON
|
||||
record states only its statuses. The description then lists the replayed
|
||||
records and the evidence ID, and the whole catalog stays within its
|
||||
serialization reservation, which the summaries and MCP annotations are charged
|
||||
to.
|
||||
|
||||
Over MCP, every tool also carries annotations: `readOnlyHint` is true for the
|
||||
safe methods (`GET`, `HEAD`, `OPTIONS` and `TRACE`) and for query `POST`s (a
|
||||
path segment such as `search` or `query`); `destructiveHint` is true for `DELETE` and left unset for other
|
||||
writes, so the MCP default (destructive) applies to them, and read-only tools
|
||||
omit it because clients ignore it there; `idempotentHint` is true for the safe
|
||||
methods, `PUT` and `DELETE`; and `openWorldHint` is false for every tool,
|
||||
because answers come from the capture rather than the captured application. The
|
||||
hints describe the captured method; replay itself changes nothing. The card
|
||||
keeps the `name`, `description` and `inputSchema` of the echo example's tool
|
||||
shape and carries no annotations.
|
||||
|
||||
Path parameters are required strings whose
|
||||
description names the segment index, the templating rule and the observed
|
||||
values (sampled within the list budget above; the manifest keeps them all);
|
||||
query parameter names are optional strings; write methods accept an
|
||||
query parameter names accept an optional string or array of strings (for
|
||||
repeated values in captured order); write methods accept an
|
||||
optional `body` object described by the recorded top-level key types. Each
|
||||
input keeps its own argument: a query name equal to a path parameter's name is
|
||||
advertised as `query_<name>`, a query name longer than 64 characters as
|
||||
@@ -344,8 +390,11 @@ In replay, `extensions`, `operations` and `children_environments` are fixed to
|
||||
`null`, `[]` and `null`: a replay environment declares no extensions, no
|
||||
data-plane operations and no children. Served
|
||||
[from the state](#serve-from-the-state), the card declares the three data-plane
|
||||
operations and one intake extension instead, leaves write tools out and
|
||||
describes each tool as answering from the state where the state backs it.
|
||||
operations and one intake extension instead, and the catalog holds the read
|
||||
tools and only the write tools whose effect the capture confirmed: a read tool
|
||||
is described as answering from the state where the state backs it, and a
|
||||
served write tool by the effect it applies to the state and the quoted body members it
|
||||
accepts.
|
||||
|
||||
## Serve from the state
|
||||
|
||||
@@ -368,7 +417,8 @@ A state that is unavailable does not stop the server: it logs a warning naming
|
||||
the error `code` and message before it binds, then serves replay. The state is
|
||||
unavailable when it cannot be derived, such as from a
|
||||
`capture_browser_scenario` capture that selected header values but no response
|
||||
bodies or over the view's budget, and when its catalog under the served name
|
||||
bodies or over the view's budget, when `data/get` would write it past the 32 MiB
|
||||
`data/add` intake limit, and when its catalog under the served name
|
||||
exceeds the [discovery reservation](#what-a-manifest-is). That check runs
|
||||
first, so no state is derived for it, and replay is then admitted exactly as
|
||||
with `--replay-only`. `--replay-only`
|
||||
@@ -385,24 +435,70 @@ member reports which applied:
|
||||
|
||||
Each read tool answers according to its view in the state:
|
||||
|
||||
| View | Answer |
|
||||
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `item` | The entity the path arguments name, rendered into the recorded envelope of `envelope_ordinal`. Arguments match as replay matches them: each collection segment equals the held collection's segment as written or after percent-decoding, and the identity is the last argument percent-decoded, then as written; values are never re-split on `/`. Any entity the state holds answers, including one `data/add` loaded; query arguments only decide `replay.exact_match`. An entity the state does not hold, or one lacking a field every recording carried, is a tool error; a body is never invented. |
|
||||
| `list` | When the arguments name one of the lines the view checked exactly (its latest recordings before the first related write; every path and query value equal to the recording's, and every recorded query parameter supplied), that recorded envelope with its array rendered from the state: every entity of the collection in state order for `membership: "all"`, or the recorded members still held. A member lacking a field every recording carried makes the call a tool error rather than a partial list. |
|
||||
| `document` | When the arguments name the document's checked line exactly, the state's value for it; a tool error when the state holds none. |
|
||||
| `recorded` | The recording, as replay answers it. |
|
||||
| View | Answer |
|
||||
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `item` | The entity the path arguments name, rendered into the recorded envelope of `envelope_ordinal`. Arguments match as replay matches them: each collection segment equals the held collection's segment as written or after percent-decoding, and the identity is the last argument percent-decoded, then as written; values are never re-split on `/`. Any entity the state holds answers, including one `data/add` loaded; query arguments only decide `replay.exact_match`. An entity the state does not hold answers the tool's latest recorded 400, 404 or 410 response with `state.view` `missing`, or is a tool error when none was recorded; one lacking a field every recording carried is a tool error, unless a read showed the application leaves that field out; a body is never invented. |
|
||||
| `list` | When the arguments name one of the lines the view checked exactly (its latest recordings before the first related write; every path and query value equal to the recording's, and every recorded query parameter supplied), that recorded envelope with its array rendered from the state: every entity of the collection in state order for `membership: "all"` or a line `all_record_ordinals` names, or the recorded members still held. A call with no query argument answers from such a line of the collection its path arguments name that only pages its list, with `replay.exact_match` false. On a line the view's `query` answers, and for a call whose every query argument has a role there (an argument-less call aside), the answer is the query evaluated over the state: filtered, searched, sorted and paged, with counters at the number listed and `query.totals` at the number matched, and `state.membership: "query"`; such a call answers on a query or whole line of its collection with `replay.exact_match` false. A value an `inert` parameter never recorded, or a parameter without a role, replays its recording. A member lacking a field every recording carried makes the call a tool error rather than a partial list. |
|
||||
| `document` | When the arguments name the document's checked line exactly, the state's value for it; a tool error when the state holds none. |
|
||||
| `recorded` | The recording, as replay answers it. |
|
||||
|
||||
A read with repeated query values uses replay, because the state query model
|
||||
does not infer repeated-parameter semantics. A repeated-query write is refused
|
||||
before it can change state for the same reason.
|
||||
|
||||
An item or list view that always spells a clock field otherwise than the
|
||||
entity's stored value names that spelling in `clock_formats`, and a value it
|
||||
never recorded, such as a created entity's clock, is rendered in it: a list that
|
||||
writes `+00:00` where item reads write `Z` lists a new entity the same way.
|
||||
|
||||
A list or document call that names no checked line, including a line recorded
|
||||
after a write or with other query values, answers from the recording. Every
|
||||
answer has the replay shape plus `state`: `{"source": "state", "view": …}`
|
||||
naming the entity, collection or document path, or `{"source": "recording",
|
||||
"reason": …}` with the view's reason, `no-view` or `unrecorded-request`. A
|
||||
"reason": …}` with the view's reason, `no-view`, `unrecorded-request`, `page-exceeded` (a call naming a page of a whole list that the collection has outgrown) or `projection` (a call to an item tool whose recordings asked for some fields only, naming such a parameter for an entity the state holds; the answer is a recording, so it does not show served writes). A
|
||||
state answer carries the base record's status, content type and `replay`
|
||||
provenance with `truncated: false`; one whose JSON would exceed 256 KiB is
|
||||
refused as a `resource_constraint` tool error rather than cut. Serving is
|
||||
read-only: `POST`, `PUT`, `PATCH` and `DELETE` tools, other than query `POST`s,
|
||||
are not served, so nothing a call does changes the state. Query `POST`s stay
|
||||
served and answer from their recordings with the reason `query-body`.
|
||||
refused as a `resource_constraint` tool error rather than cut. Extraction does
|
||||
not state-back a document whose rendered JSON exceeds 256 KiB; that read stays
|
||||
recorded (`rendered-oversize`) and replays the captured body. Query `POST`s
|
||||
stay served and answer from their recordings with the reason `query-body`.
|
||||
|
||||
A line establishes whole-collection membership only from the beginning:
|
||||
`offset`, `start`, `_start` and `page` must be zero when present. Positive or
|
||||
malformed positions do not by themselves establish whole membership. A separate
|
||||
query model may describe supported paging; an empty later page cannot start
|
||||
returning earlier entities merely because it was empty in the capture.
|
||||
|
||||
`POST`, `PUT`, `PATCH` and `DELETE` tools are served only when the state's
|
||||
[write plan](web-network-captures.md#environment-state) for them is served:
|
||||
the capture's later reads confirmed the effect the plan models. Other write
|
||||
tools are not served, so no call claims a change it does not make; each one's
|
||||
plan states why in its `reason`. A served write changes the live state, which
|
||||
every MCP session and `data/get` then see:
|
||||
|
||||
| Effect | Call |
|
||||
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `create` | Adds an entity to the collection the path names, built from the observed entity with each ruled field taken from the call or generated, at the plan's `insert` position. A plan tied to its exemplar's collection writes only there. |
|
||||
| `update` | Sets the sent members on the entity the path names, constants for members accepted only with their recorded value, and the clock, increment, slug, unique and renewed changes the plan models. |
|
||||
| `delete` | Removes the entity the path names. |
|
||||
| `document` | Merges the body into the plan's document object, or replaces it for `PUT`. |
|
||||
|
||||
Its answer has the status and content type of the plan's recorded response,
|
||||
with the written entity or its identity rendered in, no body, or the recorded
|
||||
body. A call whose body is not an object, sends a member the capture did not
|
||||
show stored, sends a fixed member with another value or a member of another
|
||||
JSON type, or lacks a required member is a tool error naming the accepted
|
||||
members; so is a rendered answer missing a field the recorded response
|
||||
carried, and an update or delete of an entity the state does not hold answers
|
||||
the recorded 400, 404 or 410 of the tool or of an item view of the type, if
|
||||
any. A refused call leaves the state unchanged. Values a write generates are
|
||||
deterministic: the clock starts at `write_clock` and advances one second per
|
||||
served write, sequences take one past both the largest held value and the
|
||||
largest they generated, and UUIDs and tokens derive from the state Evidence
|
||||
id, tool, field and write count, skipping held values. `data/reset` and
|
||||
`data/add` restart the clock, counter and sequences, so the same calls after a
|
||||
reset give the same state. Answers carry `state: {"source": "state", "view":
|
||||
"create" | "update" | "delete", …}` or `"document-write"`.
|
||||
|
||||
The data plane serves three JSON-RPC methods:
|
||||
|
||||
@@ -436,18 +532,29 @@ names its category in `error.data.reason`: `not-found`, `permission`,
|
||||
downloads, and `cancelled` for a download the server's stop or its caller's
|
||||
departure ended.
|
||||
|
||||
Served creates also bound additional collection history since the last reset
|
||||
or `data/add` to 1 MiB of deterministic accounting: UTF-8 bytes for each new
|
||||
collection spelling and its possible sequence keys, plus a 64-byte allowance
|
||||
per collection and potential sequence-key record. The score bounds identifier
|
||||
payload and a fixed record allowance; it is not a measurement or guarantee of
|
||||
process memory. Collections
|
||||
already present in the Evidence or loaded state are part of the state itself;
|
||||
the store indexes their unique spellings so they remain known after deletion,
|
||||
but they do not consume this additional-history budget. A create that would
|
||||
exceed the budget is refused before the state changes. `data/reset` or `data/add`
|
||||
clears generated history; if the same calls would hit the limit again, use
|
||||
fewer distinct collection paths. The 1 MiB score ceiling is 1/32 of the
|
||||
separate 32 MiB state-intake ceiling, reserving a small, explicit allowance
|
||||
for identifiers retained beyond the loaded state. A loaded-state path that is
|
||||
later deleted and then introduced again may consume the additional-history
|
||||
budget when the store must retain it beyond the source entity.
|
||||
|
||||
Stopping the server cancels every pending call, and a caller that leaves before
|
||||
its reply cancels its own: a download in progress ends, and calls not yet run
|
||||
are answered `-32000` with `error.data.reason` `cancelled` without running. A
|
||||
cancelled call leaves the state unchanged, and shutdown never waits for a
|
||||
download.
|
||||
|
||||
A `file://` state file whose close fails stays owned by the server, and
|
||||
the `data/add` gets `-32000`. The next `file://` load retries that close first
|
||||
and, while it still fails, answers `-32000` without reading another file;
|
||||
inline and `https://` documents still load. Closing the server retries it once
|
||||
more and fails with the unfinished close rather than dropping the descriptor.
|
||||
|
||||
One `/agentenv` response carries at most 64 MiB of replies, twice the 32 MiB
|
||||
a loaded document may hold: room for a `data/get` of a loaded state, while a
|
||||
batch of reads cannot multiply a large state into one body. Replies are
|
||||
@@ -483,7 +590,10 @@ id are unique; `view_fields` is optional and names item or list views of its
|
||||
type. Views render their values over the entity's fields, so a view's values
|
||||
must not set the type's identity field to a value whose text differs from the
|
||||
entity's `id`. Spell a collection as requests spell it, as `data/get` reports it: list
|
||||
calls find entities under the checked line's recorded path. Each document
|
||||
calls find entities under the checked line's recorded path. State collection
|
||||
identity preserves repeated separators inside captured paths: `/api/books`
|
||||
and `/api//books` are distinct. A single trailing slash continues to name the
|
||||
same collection. Each document
|
||||
names a `document` view once, at its initial document's `path`. The `version`,
|
||||
and the `state_evidence_id` and `types` that `data/get` reports, must match
|
||||
the served state, so a `data/get` result loads back unchanged. A number without
|
||||
@@ -531,14 +641,17 @@ The card declares the operations and what `data/add` accepts:
|
||||
}
|
||||
```
|
||||
|
||||
The state is a projection of recorded reads. List and document calls answer
|
||||
from the state only for the lines their views checked, and every recorded view
|
||||
answers from recordings; item calls answer for any held entity but render only
|
||||
the envelope one recording carried. Values copied outside entity objects,
|
||||
derived values and counters other than those that count a list stay as
|
||||
recorded; no write has an effect. An exported bundle carries no state file:
|
||||
its server derives the state at startup, as the export does to predict what it
|
||||
serves.
|
||||
The state starts as a projection of recorded reads and changes only through
|
||||
served write tools and the data plane. List and document calls answer from the
|
||||
state only for the lines their views checked, and every recorded view answers
|
||||
from recordings; item calls answer for any held entity but render only the
|
||||
envelope one recording carried. Values copied outside entity objects, derived
|
||||
values and counters other than those that count a list stay as recorded, and a
|
||||
served write changes only the one entity or document it writes: side effects
|
||||
on counters, relations and copies of entities in other collections, reordering
|
||||
after an update and referential rules on delete are not modelled. An exported
|
||||
bundle carries no state file: its server derives the state at startup, as the
|
||||
export does to predict what it serves.
|
||||
|
||||
## Export a bundle
|
||||
|
||||
@@ -553,7 +666,7 @@ agent-env run ./grafana-example
|
||||
```text
|
||||
grafana-example/
|
||||
README.md provenance, what it serves, run command, rights note
|
||||
envs/grafana-example/Dockerfile pinned image: node:24.18.0-bookworm-slim + rea-agents@<this version>
|
||||
envs/grafana-example/Dockerfile pinned image: node:24.22.1-bookworm-slim + rea-agents@<this version>
|
||||
envs/grafana-example/env.toml environment_name = "grafana-example"
|
||||
envs/grafana-example/manifest.json byte-exact copy of manifest.json
|
||||
envs/grafana-example/evidence.json byte-exact copy of capture.json
|
||||
@@ -606,8 +719,8 @@ name from Python sources the image does not have.
|
||||
|
||||
`verify.py` is the framework's `async def verify(mcp_url)` shape over its
|
||||
Python MCP client: it lists the tools and checks the count equals the number
|
||||
the bundle serves (the manifest's read tools from the state, every manifest
|
||||
tool in replay), calls one tool with no arguments and checks the call did not
|
||||
the bundle serves (from the state, the manifest's read tools and the write
|
||||
tools whose effect the capture confirmed; every manifest tool in replay), calls one tool with no arguments and checks the call did not
|
||||
fail and its `status` is the expected one, and returns one `serve` result
|
||||
whose description reports both checks. The tool is the first served `GET` tool
|
||||
without path parameters whose answer to no arguments is not an error, and the
|
||||
@@ -625,13 +738,85 @@ The README written into the bundle records the capture artifact's SHA-256, the
|
||||
capture and manifest Evidence ids, the manifest view digest, the served tool
|
||||
count, the derived state's Evidence id or that no state is served, and the
|
||||
package source. It says what the environment serves: read tools from the state
|
||||
the capture observed, the `/agentenv` data plane on it and no write tools yet,
|
||||
replay when the state is unavailable, and `--replay-only` for pure replay; it
|
||||
the capture observed, the `/agentenv` data plane on it and the write tools
|
||||
whose effect the capture's later reads confirmed, replay when the state is
|
||||
unavailable, and `--replay-only` for pure replay; it
|
||||
says which applies to this bundle, with the error code and message when the
|
||||
state is unavailable, and that neither is emulation and served
|
||||
content is untrusted data. It states that the recorded content belongs to the
|
||||
captured application and must not be published without the rights to it.
|
||||
|
||||
## Measure fidelity against the application
|
||||
|
||||
An environment agrees with its own capture by construction. What matters to an agent is how it answers the calls the
|
||||
capture did not make, what it shows after a write, and how it fails. `rea environment-compare` measures that against the
|
||||
application itself:
|
||||
|
||||
```sh
|
||||
rea environment-compare manifest.json --evidence capture.json \
|
||||
--probe probe-crud.json --probe probe-reads.json --json
|
||||
```
|
||||
|
||||
Each `--probe` is capture Evidence (`inspect-web-network-capture` of a HAR, or `capture-browser-scenario`) of one call
|
||||
sequence made against the live application, seeded as it was for the capture and reset before the sequence. The command
|
||||
makes no network call: whoever records the probes drives the application with its own credentials. For each probe it
|
||||
resets the environment's state, takes the requests in the order they were made (record order when any lacks a start time), matches each to the manifest tool of the
|
||||
same method whose path template fits with the most literal segments (a format-rule parameter must fit its format once
|
||||
percent-decoded). A path argument is the raw segment, which the environment decodes once.
|
||||
It answers the call as the served environment would, and compares that answer with the application's.
|
||||
|
||||
A re-seeded application holds the same entities under other ids, so the comparison maps them. Objects in the two answers
|
||||
to one call pair by a natural key, a string field unique on each side that both share, such as a name or a slug; their
|
||||
identifier fields (`id`, `uuid`, `guid`, and names ending in `_id`, `Id`, `ID`, `_uuid` or `Uuid`), and those of two single
|
||||
answers such as a create's, map the live value to the environment's, including a create that returns only the new id.
|
||||
Ids are learned only from an answer the environment
|
||||
gave that call itself, from its state or a recording of that very call, request line and body, never from another call's
|
||||
recording replayed in its place and never from a recording whose body the probe omitted. The answer's own `id`, `uuid` or `guid` also maps within the collection the call names, since
|
||||
two collections can reuse a live id, and an equal pair stays in that collection. A live id in a later request's path, query or body is translated before the
|
||||
environment answers, a path parameter by the collection the live path names (a nested collection keeps its parent values, each decoded once, and a literal route segment stays), except a query value that pages a list, such as `limit`
|
||||
or `page`. Each call is checked against the served tool's input schema first, as the MCP server checks it. After mapping, two clock values compare by format only (ISO-8601 strings, and epoch numbers under
|
||||
`at`, `time`, `date`, `timestamp`, `created`, `updated` or `modified` field names, including snake-case and camel-case forms), and two different values each side generated on its own compare equal: both UUIDs, or one length of
|
||||
eight or more with the same character classes and a digit. The report counts each kind of normalised value.
|
||||
ISO clock offsets are accepted only within RFC 3339's `00`–`23` hour and `00`–`59` minute ranges.
|
||||
Timestamp ordering retains submillisecond precision when the source records it.
|
||||
|
||||
Comparison keeps response representations distinct: JSON values compare structurally, text compares as text, and a
|
||||
retained base64 body compares by bytes (including with UTF-8 text carrying those same bytes), never by its base64
|
||||
spelling. ID mappings apply at identifier fields, `ids`/`uuids`/`guids` lists, an entity's own identity within its
|
||||
collection, and a string field learning confirmed as a state-held ID. ID mappings leave other numeric and string values unchanged. A
|
||||
global conflict involving an equal pair is not used to normalize either pair; the report counts it as an ID conflict.
|
||||
|
||||
A step agrees when the statuses and the normalised bodies are equal. The report gives agreement overall, per probe and
|
||||
per tool, `agreement_ignoring_order` for steps that differ only in item order, and each step's differences, at most 20,
|
||||
with a JSON pointer and both values cut short:
|
||||
|
||||
| Category | Meaning |
|
||||
| --------------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
| `status` | The statuses differ |
|
||||
| `missing-field` | The application's object has a member the environment's lacks |
|
||||
| `extra-field` | The environment's object has a member the application's lacks |
|
||||
| `value` | Values differ, or one is an object or array and the other is not |
|
||||
| `length` | Arrays differ in length, or not every item pairs |
|
||||
| `order` | Paired items come in a different order |
|
||||
| `clock-format` | Both are clocks, in different formats |
|
||||
| `refused` | The environment refused the call |
|
||||
| `not-served` | The request's tool is one the environment does not offer, such as a withheld write |
|
||||
| `no-tool` | No manifest tool matches the request |
|
||||
| `unmapped-id` | The application answered with success and the environment did not, for a path id the comparison never mapped |
|
||||
|
||||
What a probe did not observe is not counted as the application's behaviour. A record without a usable request line,
|
||||
such as a redacted URL or a transaction the capture cannot attribute, is not replayed, nor is a request to another
|
||||
origin than the application's (`other-origin`: the probe's origin with the most JSON-like records, as the manifest
|
||||
chooses its own), and a request with no recorded
|
||||
answer is made, since it may have changed the application, but not compared: each probe lists them under `unobserved` with the reason, and the summary counts them. A live
|
||||
body the probe did not record compares by status only and is counted as `unobserved_bodies`, unless the answer never
|
||||
carries one (204, 205, 304, `HEAD`). A browser probe captured without `capture.network.response_body` is refused, as
|
||||
is one that makes POST, PUT or PATCH calls without `capture.network.request_body`.
|
||||
|
||||
Agreement covers only the calls the probes make, after the mapping the answers allow. Values compared by form, clocks
|
||||
and generated values, can still differ in content, and an equal answer after a write shows the state matched for that
|
||||
read, not that the write had no other effect.
|
||||
|
||||
## Compatibility verification
|
||||
|
||||
`npm run verify:agentenv:environment` is the hosted `real-agentenv` lane
|
||||
|
||||
@@ -171,8 +171,14 @@ the same source byte limit and explicit truncation reporting.
|
||||
## Interpret the result
|
||||
|
||||
- Package inspection retains decoded manifest XML, summary declarations,
|
||||
permissions and class/resource counts. Summary fields are extracted by the
|
||||
upstream engine and should be checked against the retained XML when needed.
|
||||
permissions and class/resource counts. REA's bridge selects the exact root
|
||||
`AndroidManifest.xml` resource by original archive name and manifest type,
|
||||
independently of asset order. One namespace-aware JDK XML parse supplies
|
||||
summary attributes and direct permission/SDK declarations; namespace prefixes
|
||||
and XML entity spelling do not change their values. Raw decoded XML is retained
|
||||
exactly and only its displayed text is subject to the existing source byte cap.
|
||||
Summaries use the complete selected XML before that cap. Document types are
|
||||
unsupported; parsing does not load external DTDs, schemas, or XInclude files.
|
||||
Signature verification is explicitly `not_performed`.
|
||||
- Class search filters the engine's cached top-level names before transferring
|
||||
pages, then follows contiguous inventory positions without rescanning earlier
|
||||
@@ -256,6 +262,10 @@ such as
|
||||
`libreactnativejni.so`, `libreactnative.so`, `libhermes.so`,
|
||||
`libhermes_executor.so`, `libflutter.so`, and `libunity.so`; unrelated names
|
||||
such as `libcommunity.so` and `libreactivity.so` do not identify those families.
|
||||
The signing list retains the `META-INF/MANIFEST.MF`, `.SF`, `.RSA`, `.DSA`, and
|
||||
`.EC` paths selected by Android's v1 verifier, including nested paths. These are
|
||||
inventory metadata candidates, not proof that a v1 signature verifies or that
|
||||
the APK is signed; use `inspect-apk-signature` for signature analysis.
|
||||
The bridge basis is inferred from the native path and repeated for each managed
|
||||
component, so it does not identify a specific JNI binding. Bridge hypotheses form a DEX/JVM-class by native-library
|
||||
Cartesian product. The projection computes the product and exact serialized
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
# APK signature schemes
|
||||
|
||||
REA reads the signing of a selected local Android APK (or ZIP/AAB) statically,
|
||||
so an analyst can answer **who signed this, under which schemes, and whether the
|
||||
declared content digests match these bytes** before trusting or triaging it. The reader
|
||||
is in-process and needs no external engine: it parses the ZIP tail and the APK
|
||||
Signing Block, reads certificates with the platform X.509 parser, and
|
||||
recomputes the content digest. No Android code executes, and no device or
|
||||
`adb` is involved.
|
||||
|
||||
CLI and MCP share one workflow and return artifact-bound Evidence inline.
|
||||
|
||||
```sh
|
||||
rea inspect-apk-signature /path/app.apk
|
||||
```
|
||||
|
||||
## Selected facts and retained Evidence
|
||||
|
||||
MCP defaults to a summary with scheme presence, signer certificate fingerprints,
|
||||
row counts, posture and explicit coverage. `detail: "complete"` returns the full
|
||||
report. A selected page can answer a narrower question in the acquisition call:
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "/path/app.apk",
|
||||
"view": {
|
||||
"collection": "signers",
|
||||
"schemes": ["v3"],
|
||||
"fields": ["certificate_sha256"],
|
||||
"limit": 32
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The returned `parent_evidence_id` identifies the retained complete report.
|
||||
Subsequent reads use `inspect_analysis_view`, including after the APK is deleted:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": {
|
||||
"kind": "retained-evidence",
|
||||
"evidence_id": "<returned parent_evidence_id>"
|
||||
},
|
||||
"view": {
|
||||
"kind": "apk-signature",
|
||||
"collection": "digests",
|
||||
"signer_ids": ["<returned signer id>"],
|
||||
"fields": ["signature_algorithm_id", "algorithm", "matches_apk"],
|
||||
"offset": 0,
|
||||
"limit": 32
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Collections are `signers`, `digests` and declared `lineage` nodes. `ids`,
|
||||
`signer_ids` and `schemes` filters intersect; omitted filters select all available
|
||||
records and `[]` selects none. Omitted `fields` returns every collection column;
|
||||
`fields: []` retains identity and relationship links. IDs include the complete
|
||||
APK digest, scheme and source ordinal; child records retain `signer_id` and
|
||||
`signer_index`, and declared certificates retain their raw-DER SHA-256 identity.
|
||||
Lineage pages expose `previous_id` when selected. Certificate fingerprints can
|
||||
be composed across versions without treating a declaration as verified identity.
|
||||
|
||||
Page coverage describes examined declared records. Exhausting a page does not
|
||||
establish certificate authenticity, platform acceptance, v1 entry coverage or a
|
||||
verified rotation. Partial decoding and its reason remain visible even when a
|
||||
lineage page contains no rows. A weak cache reuses validated immutable report
|
||||
facts; each read checks its parent subject, and new file inspections read again.
|
||||
|
||||
CLI defaults to complete delivery. A compact one-shot response requires a complete
|
||||
Evidence export:
|
||||
|
||||
```sh
|
||||
rea inspect-apk-signature /path/app.apk --detail summary \
|
||||
--view '{"collection":"signers","fields":["certificate_sha256"]}' \
|
||||
--evidence_output /path/app-signing-evidence.json --json
|
||||
```
|
||||
|
||||
The export contains the same complete parent used by MCP. Historical CLI pages
|
||||
use `inspect-analysis-view` with an `evidence-file` source record. The CLI and MCP
|
||||
share the application workflow, projection, retention and publication owners.
|
||||
|
||||
## What it reports
|
||||
|
||||
- **Schemes present:** v1 (JAR signing, from the central directory), and the
|
||||
APK Signing Block's v2, v3 and v3.1. v1 follows apksig's selection: entries
|
||||
under `META-INF/` at any depth ending in `.SF`, or in `.RSA`/`.DSA`/`.EC`
|
||||
(case-sensitive). v1 is `present` only when a signature block has its
|
||||
matching `.SF` file (`META-INF/x/CERT.RSA` pairs with `META-INF/x/CERT.SF`);
|
||||
`signature_files` and `block_files` list every candidate either way.
|
||||
- **Per v1 signer** (each block paired with its `.SF`): REA inflates the block
|
||||
and reads its PKCS#7 `SignedData`. `certificate` is the certificate the
|
||||
block's one `SignerInfo` names by `issuerAndSerialNumber` or
|
||||
`subjectKeyIdentifier` (not by position), with the same facts and raw-DER
|
||||
SHA-256 as a v2/v3 signer, so a v1-only APK can be fingerprinted and
|
||||
clustered with v2/v3-signed ones. apksig resolves only
|
||||
`issuerAndSerialNumber`, so its v1 verification fails for a block whose
|
||||
`SignerInfo` uses `subjectKeyIdentifier`: REA still reports the declared
|
||||
certificate (`identified_by: subject-key-identifier`), adds a limitation,
|
||||
and treats that signer as unknown in `v1_signers_match_block_signers`. `certificates` lists every certificate the
|
||||
block carries (SHA-256 and subject) and `signer_infos` gives each
|
||||
`SignerInfo`'s certificate and digest/signature algorithm OIDs. The PKCS#7
|
||||
`SignedData` envelope is read as BER, including constructed signature OCTET
|
||||
STRINGs; each embedded certificate is still interpreted as DER by the X.509
|
||||
owner.
|
||||
`certificate` is `null` when the block has more than one `SignerInfo` (with
|
||||
nothing verified there is no single signer) or names a certificate it does
|
||||
not carry. A block that cannot be read (malformed ASN.1, an unsupported
|
||||
compression method, Zip64 sizes, a local header that disagrees with the
|
||||
central directory on the name, data-descriptor flag, CRC-32 or a size, as
|
||||
apksig refuses it, or over a bound) keeps its names and carries
|
||||
`decode_error`; it is never reported as an absent signer. apksig ignores
|
||||
the ZIP encryption flag (bit 0), so a block that sets it is read as stored:
|
||||
the PKCS#7 decoding decides (bytes that really are encrypted fail to
|
||||
decode), and a limitation names the block.
|
||||
apksig rejects the v1 signature of an archive whose central directory
|
||||
holds any name more than once ("Duplicate entry"). REA checks every entry:
|
||||
a limitation names the first few duplicates (JSON-quoted; a name over 256
|
||||
bytes is cut there and its stored length given) and counts the rest, and a
|
||||
signer whose block, `.SF` or `META-INF/MANIFEST.MF` name is duplicated
|
||||
(one signer per block name) carries `decode_error`
|
||||
`duplicate entry: <name>`, so a duplicated manifest marks every signer.
|
||||
A duplicate outside those names leaves the signers as declared.
|
||||
Names are compared as apksig compares them, as Java strings decoded from
|
||||
UTF-8: malformed bytes become U+FFFD, so `dup\xff` and `dup\xfe` are one
|
||||
name (apksigner: `Duplicate entry: dup�`). REA reproduces Java's
|
||||
replacement rather than WHATWG `TextDecoder`'s; the two differ for encoded
|
||||
surrogates (`ED A0..BF`), which Java replaces as one unit. This was checked
|
||||
against OpenJDK 25's `new String(bytes, UTF_8)` on about 300,000 malformed
|
||||
and well-formed sequences, including a leading byte-order mark, which Java
|
||||
keeps; other Java runtimes are not checked. The same
|
||||
decoding names v1 entries and compares a local header's name with the
|
||||
central directory's; as in apksig, a local name longer in bytes than the
|
||||
directory's is refused before decoding. apksig takes the record count from the classic
|
||||
end-of-central-directory record's 16-bit field and ignores a Zip64 count,
|
||||
so it reads only the first 65,535 records of a larger directory: the
|
||||
limitation then says so, counts as duplicates for apksig only names whose
|
||||
second copy lies within those records, and names separately those
|
||||
duplicated only past them. REA still reads v1 signing entries, and flags
|
||||
duplicated signing names, from every record, so past record 65,535 it
|
||||
reports signers apksig would not see.
|
||||
Bytes after the block's `ContentInfo` are ignored, as apksig's BER parser
|
||||
ignores them, and a limitation names the block and their count.
|
||||
- **Per signer:** the certificate's **SHA-256 fingerprint over the raw embedded
|
||||
DER** (the same value `apksigner --print-certs` prints), plus subject, issuer,
|
||||
serial, ISO 8601 validity and public-key algorithm when the X.509 parser can
|
||||
read them (each is `null` otherwise); raw signature algorithm IDs, declared
|
||||
digest hex and digest algorithms, signature lengths and public-key length; and for
|
||||
v3/v3.1 the signer's declared min/max SDK.
|
||||
- **Key rotation (v3/v3.1):** the declared proof-of-rotation lineage, oldest
|
||||
first. Each node carries its certificate and the capability flags **retained
|
||||
by that node's own certificate** after rotation (installed data, shared UID,
|
||||
permission, rollback, auth). A lineage attribute that cannot be decoded is
|
||||
reported with `decode_error`, never silently emptied.
|
||||
- **Source stamp:** whether a source-stamp block is present and the stamp
|
||||
certificate it declares (the V2 stamp block is preferred over V1, as apksig
|
||||
does). `certificate` is `null` when no stamp is present, or when the block
|
||||
could not be decoded and `decode_error` says why. Stamp signatures are not
|
||||
verified.
|
||||
- **Declared digest consistency:** for SHA-256/SHA-512 digests, REA recomputes
|
||||
the v2/v3 content digest and reports `matches_apk` per digest and
|
||||
`posture.self_consistent`. This only shows that the **declared** digest
|
||||
equals the digest of the current bytes. It is **not a signature
|
||||
verification**: anyone who changes the bytes can recompute the digest and
|
||||
write it into the signed data, and REA still reports `true` while
|
||||
`apksigner verify` rejects the APK. A changed byte with an unchanged
|
||||
declared digest reads `false`.
|
||||
- **Posture** (derived from the facts above):
|
||||
- `v1_only`: v1 is present and no v2/v3/v3.1 block is. The v1
|
||||
`X-Android-APK-Signed` marker is not read, so this cannot distinguish an
|
||||
APK signed only with v1 from one whose v2/v3 block was removed.
|
||||
- `schemes_agree_on_signer` (observed): every present block scheme presents
|
||||
the same _set_ of signer certificates. An extra signer in one scheme is
|
||||
disagreement; a signer without a certificate makes it `null` (unknown).
|
||||
Build-tools 33+ rotate through v3.1 by default, so a rotated app usually
|
||||
reads `false` here and `true` below.
|
||||
- `signer_change_declared_by_rotation` (declared): the signers differ, but
|
||||
each appears in a lineage the APK declares. Read the two together: a
|
||||
rotated APK shows `false` / `true`; signers that differ with no declared
|
||||
lineage containing them show `false` / `false`. It is `null` when a
|
||||
signer's identity is unknown, or when the signers differ and a declared
|
||||
lineage could not be decoded.
|
||||
- `v1_signers_match_block_signers` (observed): the v1 signer certificates
|
||||
equal what the lowest block scheme that has signers (v2, else v3, else
|
||||
v3.1) expects v1 to carry. That is its signer set, except that a v3/v3.1
|
||||
signer declaring a rotation lineage expects the lineage's first
|
||||
(original) certificate, as apksig requires. `false` is notable: the JAR
|
||||
signature names a different key than the block signature. A key rotation
|
||||
keeps v1 (and v2) on the original key, so it reads `true` while
|
||||
`schemes_agree_on_signer` reads `false`, with or without v2. `null` when
|
||||
v1 or a block scheme is absent, any signer's identity is unknown (a
|
||||
`decode_error`, a `null` certificate or a `subjectKeyIdentifier`
|
||||
`SignerInfo`), or the lineage's original certificate cannot be
|
||||
identified; a limitation then says why.
|
||||
- `strongest_scheme`, `rotation_present`, `source_stamp_present`,
|
||||
`self_consistent`.
|
||||
|
||||
## What it does not claim
|
||||
|
||||
This is **declared identity and digest consistency, not trust**. No signature
|
||||
is cryptographically verified (including the v1 PKCS#7 signature and the
|
||||
`.SF`/`MANIFEST.MF` digests, so a v1 signer is reported even where `keytool`
|
||||
or `apksigner` reject the archive), certificate chains and revocation are not
|
||||
evaluated, and nothing here says an app is authentic. `self_consistent: true`
|
||||
means the declared digest equals the digest of the current bytes; it is not a
|
||||
signature verification, and it does not prove who made the bytes. Rotation-lineage node signatures are not verified either, so a lineage is
|
||||
what the APK _declares_: an attacker who re-signs an APK can declare any
|
||||
lineage, which is why `signer_change_declared_by_rotation` is kept apart from
|
||||
the observed agreement. SHA-256 identifies exact bytes, not authenticity.
|
||||
|
||||
Not yet read: v4 `.apk.idsig` (a sibling file), verity (`0x0421`/`0x0423`/`0x0425`) digests (reported with
|
||||
`matches_apk: null`), and the v1 `X-Android-APK-Signed` marker.
|
||||
|
||||
## Bounds and errors
|
||||
|
||||
The archive is read once, bounded at 512 MiB, without following symlinks and
|
||||
with change detection. Every size and offset in the ZIP tail and signing block
|
||||
is checked against its containing section before use, including the complete
|
||||
central-directory extent before ZIP end records. A process-wide queue permits
|
||||
one active whole-file inspection and eight pending scans across provider
|
||||
instances; pending scans retain no APK bytes and can be cancelled with their
|
||||
original reason. Further requests receive a capacity error. The active slot
|
||||
is held through parsing and cleanup. Signers per scheme, v1 signers and
|
||||
lineage nodes are capped at 32 each as resource admission limits, not format
|
||||
maxima (apksig separately accepts at most 10 v1 signers). Each v1 block is
|
||||
inflated to at most 1 MiB, and its BER is read within 32 levels of nesting and
|
||||
65,536 elements, with at most 32 certificates and 32 `SignerInfo`s; BER
|
||||
indefinite lengths and constructed OCTET STRING fields are accepted. Embedded
|
||||
X.509 certificates retain their DER requirement. The report's size is
|
||||
bounded from above by those counts before anything is materialised, and the exact
|
||||
serialized size of the report together with its limitations (which repeat
|
||||
archive names) is then checked against an 8 MiB output budget (the exact check
|
||||
is authoritative); an over-budget report is refused, not truncated.
|
||||
|
||||
The whole-file reader retains read chunks and a concatenated buffer; total
|
||||
process memory exceeds the selected file's size. It also computes the complete
|
||||
file SHA-256, so inspection is not header-only. Content digests are recomputed
|
||||
at most once per SHA-256/SHA-512 algorithm during one inspection. Input,
|
||||
inflation, decoded-record and serialized-output bounds keep work finite;
|
||||
resource refusals are distinct from malformed format errors.
|
||||
|
||||
A file that is not a ZIP is refused as an unsupported target. A damaged ZIP
|
||||
(local headers but no end-of-central-directory), a central directory that
|
||||
cannot be walked or whose declared record count does not account for all of
|
||||
its bytes, or a malformed signing block or signer is an input error naming the
|
||||
scheme and reason. Signer framing includes signature records, the public-key
|
||||
field and matching signed/outer v3 SDK ranges. Suffix bytes beyond known
|
||||
fields are counted as uninterpreted, as Android readers may ignore extensions;
|
||||
their presence does not establish malformed signing.
|
||||
When the central directory is not immediately followed by
|
||||
the end-of-central-directory record (a declared-size mismatch or a Zip64
|
||||
record), the content digest is not recomputed and a limitation says so. A
|
||||
rotation attribute that cannot be decoded still counts as `rotation_present`
|
||||
(the attribute exists) and carries its `decode_error`.
|
||||
|
||||
Verified by the `verify:apk-signature` real lane. It builds a real minimal APK
|
||||
with `aapt2`, signs it with the SDK's `apksigner` (default v2+v3, v1-only with
|
||||
RSA and EC keys, v1+v2+v3 on a legacy target, a rotated key lineage with and
|
||||
without v1, rotation carried by v3.1, a source stamp, and a copy
|
||||
with one changed byte), and cross-checks REA against
|
||||
`apksigner verify --print-certs`, `apksigner lineage --print-certs` and
|
||||
`keytool -printcert -jarfile` through the CLI and MCP.
|
||||
|
||||
The real-toolchain CI lane uses pinned, checksum-verified Build Tools 36.1.0
|
||||
and platform 36 oracle files in its job workspace. It requires the existing
|
||||
host JDK and runs `npm run verify:apk-signature -- --require-tools`; absent
|
||||
oracles fail rather than silently establishing provider coverage. REA itself
|
||||
requires none of these external tools.
|
||||
@@ -96,6 +96,14 @@ still suppresses all string projection, including in this mode.
|
||||
- **Metadata comes from apktool.yml as apktool printed it.** Version codes
|
||||
keep their own spelling (`'7'` versus `7`); `package_name` is read from
|
||||
the decoded manifest, not inferred.
|
||||
Apktool 3's emitted `version: 3.x.y` header selects its single-line string
|
||||
dialect: literal hashes, single quotes, empty strings, and the text `null`
|
||||
stay part of the value; producer backslashes and Unicode escapes decode
|
||||
once. Older/tagged documents retain YAML scalar semantics; double-quoted
|
||||
values also retain YAML string semantics.
|
||||
This distinction follows the released
|
||||
[3.0.3 metadata writer](https://github.com/iBotPeaches/Apktool/blob/18b5e99cb56ff9451e8aa55b065dcf5bbd616975/brut.apktool/apktool-lib/src/main/java/brut/androlib/meta/VersionInfo.java#L49-L55)
|
||||
and [string escape owner](https://github.com/iBotPeaches/Apktool/blob/18b5e99cb56ff9451e8aa55b065dcf5bbd616975/brut.j.yaml/src/main/java/brut/yaml/YamlStringEscapeUtils.java#L55-L116).
|
||||
- **The manifest is the decoded text**, bounded at 512 KiB and reported as
|
||||
truncated when larger.
|
||||
- **Strings are projected verbatim.** Escaped entities stay escaped, and
|
||||
@@ -167,6 +175,6 @@ Multi-locale and table-only projection were also verified through real CLI and
|
||||
stdio MCP workflows on Linux with Apktool 3.0.3/JDK 21 against NewPipe 0.29.1,
|
||||
ApiDemos 6.0.18 and Appium Settings 8.2.1. Independent XML projection checks,
|
||||
exact facts/Evidence parity and bounded task costs are recorded in the
|
||||
[shared-decode and table-only checkpoint](../experiments/analysis-efficiency/apktool-string-tables.md).
|
||||
[shared-decode and table-only checkpoint](https://github.com/morluto/rea/blob/42e1a17d6e6c0487f17be0bae248553c4caba7f7/experiments/analysis-efficiency/apktool-string-tables.md).
|
||||
This qualifies selected resource facts, not application execution or independent
|
||||
binary resource-decoder completeness.
|
||||
@@ -220,9 +220,16 @@ satisfy a dylib dependency. `platform-mismatch` means a matching-architecture
|
||||
dylib was found but its observed platform is incompatible with the process.
|
||||
These outcomes reject that candidate; dyld search may continue and resolve a
|
||||
later candidate. Candidate outcomes describe individual search paths, while
|
||||
`resolution.status` describes the final edge. Slices follow dyld's graded
|
||||
architectures, so an `x86_64h` process also loads `x86_64`. The edge's
|
||||
`resolution` is one of:
|
||||
`resolution.status` describes the final edge. For each selected process-root
|
||||
slice, candidate slices are matched by CPU type and dyld's subtype preference
|
||||
order, independently of FAT table order. An ARMv7s root slice prefers ARMv7s,
|
||||
then ARMv7; other known ARM32 subtypes use their compatibility rows from
|
||||
[Apple's dyld source](https://github.com/apple-oss-distributions/dyld/blob/dyld-852.2/src/dyld2.cpp#L2811-L3105).
|
||||
An `x86_64h` process also loads generic `x86_64`. Unknown ARM32 subtype policy
|
||||
remains undetermined when ARM32 candidate slices exist. This is a static model
|
||||
keyed to the selected root slice; it does not observe the target device's host
|
||||
CPU or prove which slice the device will execute. The edge's `resolution` is
|
||||
one of:
|
||||
|
||||
| Status | Meaning |
|
||||
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -29,6 +29,7 @@ graph TD
|
||||
PROVIDER_OWNERS["src/providers/<br/>shared deferred client and inspection owners<br/>exact cleanup retry and attributed failures"]
|
||||
PWNTOOLS["src/native/pwntools/ + src/native/pwndbg/<br/>BYO offline ELF/core adapters<br/>owned snapshots/Python and optional core-only GDB<br/>unchanged upstream parsers, ABI structures and mapping API"]
|
||||
WASM["src/wasm/<br/>caller-supplied WABT; immutable artifact inspection<br/>owned process supervision and retryable workspace cleanup"]
|
||||
APKSIG["src/apkSignature/<br/>in-process APK Signing Block + v1 reader<br/>bounded single read, no device or execution"]
|
||||
EVM["src/evm/<br/>unchanged EVMole/WASM in bounded owned worker<br/>explicit carrier parsing and inferred interface adapter"]
|
||||
HOPPER["src/hopper/<br/>Hopper launch & Unix-socket protocol<br/>BridgeLauncher, HopperClient, protocol"]
|
||||
GHIDRA["src/ghidra/<br/>Ghidra discovery, profile & function analysis<br/>snapshot, Unix/Windows transport, bounded lifecycle"]
|
||||
@@ -101,6 +102,8 @@ graph TD
|
||||
SERVER -->|narrow record ports| RECORDS
|
||||
RECORDS --> DOMAIN
|
||||
COMPOSITION --> WASM
|
||||
COMPOSITION --> APKSIG
|
||||
APKSIG --> DOMAIN
|
||||
WASM --> PROCESS
|
||||
WASM --> DOMAIN
|
||||
COMPOSITION --> PWNTOOLS
|
||||
|
||||
@@ -215,3 +215,157 @@ Large Evidence envelopes may require a caller-configured MCP transport receive
|
||||
buffer because envelope copies add overhead. Requests honor cancellation during
|
||||
snapshot reading, directory traversal and payload hashing. The operation reads
|
||||
regular files only and rejects symbolic links.
|
||||
|
||||
## Byte entropy triage
|
||||
|
||||
`inspect_byte_entropy` / `inspect-byte-entropy` profiles any local regular file
|
||||
without an analysis engine, execution, extraction or network access.
|
||||
|
||||
```sh
|
||||
rea inspect-byte-entropy ./firmware.bin --block-size 4096 --json
|
||||
rea inspect-byte-entropy ./firmware.bin --offset 4096 --length 65536 --json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inspect_byte_entropy",
|
||||
"arguments": { "path": "/artifacts/firmware.bin", "detail": "summary" }
|
||||
}
|
||||
```
|
||||
|
||||
Complete Evidence includes `artifact` (original path, byte size and SHA-256),
|
||||
`block_size`, `window`, `file_entropy`, `thresholds`, `blocks`, `runs` and
|
||||
`limitations`. For a 4096-byte zero-filled file, the entropy fields are:
|
||||
|
||||
```json
|
||||
{
|
||||
"block_size": 4096,
|
||||
"window": { "offset": 0, "length": 4096 },
|
||||
"file_entropy": 0,
|
||||
"thresholds": { "high": 7.2, "low": 1 },
|
||||
"blocks": [{ "offset": 0, "length": 4096, "entropy": 0 }],
|
||||
"runs": [{ "offset": 0, "length": 4096, "classification": "low" }]
|
||||
}
|
||||
```
|
||||
|
||||
Offsets and lengths are decimal byte counts. Blocks begin at the requested
|
||||
`offset` (default zero); omitted `length` extends to EOF. Explicit windows past
|
||||
EOF fail rather than silently clipping. The final block may be shorter.
|
||||
`block_size` must be a power of two from 256 through 65536, default 4096. A
|
||||
window may produce at most 32,768 block rows; larger requests fail before the
|
||||
file scan with a capacity error. Choose a shorter window or larger block size.
|
||||
SHA-256 and `file_entropy` always cover the entire file, including when a window
|
||||
is selected. Empty files and empty windows are accepted; empty entropy is zero
|
||||
by convention. The tool reads the size the file reports. A file that reports size
|
||||
0, such as a Linux `/proc` entry, returns no blocks with a limitation that the
|
||||
result does not show the file is empty. File identity, size and timestamps are checked across the read;
|
||||
detected changes produce an error rather than Evidence.
|
||||
|
||||
Shannon entropy is reported in bits per byte from 0 to 8, rounded to four decimal
|
||||
places. Adjacent blocks with reported entropy at least 7.2 form `high` runs;
|
||||
blocks at most 1.0 form `low` runs. Other blocks interrupt runs. Entropy does not
|
||||
prove encryption, and this measure cannot distinguish encrypted from compressed
|
||||
data. Small blocks can underestimate entropy; the result is a triage clue.
|
||||
|
||||
MCP `detail: "summary"` retains complete Evidence in the session and returns
|
||||
file entropy, block/run counts, thresholds, the selected window, and the ten
|
||||
longest runs (ties ordered by file offset). Use its `parent_evidence_id` to
|
||||
retrieve complete Evidence, or request its summary with `inspect_analysis_view`.
|
||||
The CLI returns complete Evidence through the same service. Summary detail
|
||||
requires a session capable of retaining Evidence.
|
||||
|
||||
Reads use one block-sized buffer and a 256-entry histogram. Complete output
|
||||
can become very large because it includes one row per selected block, and
|
||||
summary delivery still retains that full list. Use a shorter length or a
|
||||
larger block size to reduce it. Full Evidence and its serialization require
|
||||
memory proportional to the number of selected blocks. The 32,768-row ceiling bounds the actual retained block objects and
|
||||
their serialized representation: a cap-sized run below produced 1,514,877
|
||||
serialized bytes and increased V8 heap use by 21.2 MiB on the measured host.
|
||||
The cap therefore bounds this output independently of file size; it is not a
|
||||
portable process-memory guarantee. Narrow the window or increase block size to
|
||||
reduce retained rows further.
|
||||
|
||||
Local service measurement (macOS arm64, Node 24.18.0, 100,000,000-byte file,
|
||||
4096-byte blocks, file already in the OS cache): first process run took 1.113 s
|
||||
wall / 1.148 s CPU with 145.3 MiB peak RSS; a second run in the same process took
|
||||
1.015 s / 1.035 s CPU, with cumulative peak RSS 155.8 MiB. Each read 100,000,000
|
||||
bytes and produced 24,415 blocks. Measurements include Evidence construction,
|
||||
summary projection and JSON serialization, with no child processes. Complete
|
||||
Evidence serialized to 1,122,303 bytes and its summary to 2,705 bytes. A
|
||||
cap-sized 134,217,728-byte sparse file with 4096-byte blocks produced 32,768
|
||||
rows and 1,514,877 serialized bytes; V8 heap use increased by 21.2 MiB and RSS
|
||||
by 18.1 MiB in that process. This separate measurement used the same macOS
|
||||
arm64 host and Node version. Cold disk I/O, token counts and an agent
|
||||
investigation were not measured; there was no previous equivalent tool to
|
||||
benchmark. These figures do not establish a portable peak-memory bound,
|
||||
constant memory for retained Evidence or faster agent task completion.
|
||||
|
||||
## Portable native exports
|
||||
|
||||
`inspect_native_exports` / `inspect-native-exports` reads the export table of an
|
||||
explicit PE or ELF image on any supported host, without an active target,
|
||||
native engine, `objdump` or Windows SDK:
|
||||
|
||||
```sh
|
||||
rea inspect-native-exports ./runtimes/linux-x64/native/libexample.so --json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inspect_native_exports",
|
||||
"arguments": { "path": "/artifacts/native/example.dll" }
|
||||
}
|
||||
```
|
||||
|
||||
The complete Evidence identifies the stable artifact snapshot by path, byte
|
||||
count and SHA-256.
|
||||
|
||||
- PE rows reproduce the export directory: each used export-address-table slot
|
||||
with its biased `ordinal` (`OrdinalBase` plus the slot index), one row per
|
||||
name (aliases share an ordinal), `address`
|
||||
as the preferred-base virtual address, or `forwarder` text when the slot
|
||||
forwards to another DLL. Unused zero-address slots are omitted;
|
||||
ordinal-only exports have a null `name`. The name-ordinal table stores an
|
||||
unbiased 16-bit EAT index; reported biased ordinals may exceed 16 bits. The
|
||||
directory's DLL name, ordinal base and timestamp are reported, and an image
|
||||
without an export directory is a complete empty inventory.
|
||||
- ELF rows list defined `.dynsym` symbols with global, weak or GNU-unique
|
||||
binding and default or protected visibility. Each row keeps `value`
|
||||
(`st_value` as stored; bit 0 marks Thumb code on 32-bit ARM), `size`, `type`
|
||||
and `binding`. ELF string tables do not declare a text encoding. Names that
|
||||
contain non-ASCII bytes are decoded as UTF-8 when those bytes form valid
|
||||
UTF-8; `name_utf8_decodable` records whether the non-ASCII name bytes are
|
||||
valid UTF-8 and `name_bytes_base64` retains those exact bytes (`null` for
|
||||
ASCII names). When they are not valid UTF-8, `name` uses a byte-preserving
|
||||
Latin-1 mapping and the raw bytes remain available. Older retained results
|
||||
report null for the newly added encoding fields. `version` is null for an
|
||||
unversioned symbol. A versioned
|
||||
symbol reports its GNU index, a name resolved from `.gnu.version_d` or
|
||||
`.gnu.version_r`, the corresponding `name_bytes_base64` and
|
||||
`name_utf8_decodable` facts, and the `hidden` flag from `.gnu.version`.
|
||||
Version names use the same UTF-8-when-valid, otherwise byte-preserving
|
||||
Latin-1 display mapping as symbol names; ELF does not declare either
|
||||
string's text encoding. Older retained results report null for the added
|
||||
version-name encoding fields. `"unknown"`
|
||||
means the symbol-version table could not be read. A hidden version is not
|
||||
the default version that a by-name `dlsym` lookup selects.
|
||||
Definition names take precedence when both tables name the same index.
|
||||
|
||||
Unreadable names, out-of-range name ordinals and unreadable forwarders are
|
||||
listed in `issues`, their entries are not reported, and coverage is `partial`.
|
||||
PE export names are bounded null-terminated byte strings and may continue
|
||||
across adjacent file-backed section mappings when the virtual bytes are
|
||||
unambiguous. Gaps, zero-fill and conflicting mappings remain unreadable names.
|
||||
Unresolved symbol versions keep their rows: the version name is null when no
|
||||
definition or requirement names the index, and `version` is
|
||||
`"unknown"` when the version table cannot be read; coverage is likewise
|
||||
`partial`. A dynamic symbol table without its null entry is malformed. An ELF
|
||||
without section headers is `unsupported`:
|
||||
enumerating dynamic symbols from the dynamic segment is not
|
||||
implemented. Mach-O exports are reported by `inspect_macho`.
|
||||
|
||||
`max_file_bytes` defaults to 256 MiB (maximum 512 MiB; CLI `--max-file-bytes`).
|
||||
Export directories in PE headers are read like those in sections. An export or
|
||||
dynamic symbol table above 262144 entries, more than 262144 rows, or more than
|
||||
16 MiB of retained names fails without partial success. Export rows do not establish that a symbol is reachable, safe to call
|
||||
or loaded at runtime.
|
||||
+110
-29
@@ -22,6 +22,13 @@ Inspect native SAZ or HAR 1.2 offline with REA, or connect Everywhere's separate
|
||||
|
||||
- `compare_web_captures` / `rea compare-web-captures` compares passive captures or exact-step-aligned browser scenarios. Scenario results commit reproducible literal normalization and expose alignment failures plus artifact-level action, screenshot, DOM, accessibility, URL, history, storage, and event differences. Missing or truncated evidence is never treated as equivalence.
|
||||
|
||||
For a compact route query, select `detail: "summary"` and a
|
||||
`view: {kind: "javascript-routes", collection: "routes", limit: 20}`. The
|
||||
shared [route inventory](javascript-route-inventory.md) preserves source IDs,
|
||||
precise locations, partial coverage, and the complete parent Evidence for
|
||||
subsequent filtered pages. Static candidates never establish complete application
|
||||
coverage or reachability.
|
||||
|
||||
For `analyze_web_bundle`, each `webmcp_declarations` entry's
|
||||
`schema_property_names` is a source-derived projection of statically known own
|
||||
property keys, not schema validation. `schema_property_names_coverage` reports
|
||||
@@ -47,6 +54,26 @@ from a protocol omission. Rejected DOM facts also mark derived URL and agent-hin
|
||||
metadata incomplete, while valid facts from other nodes and documents remain
|
||||
available in the capture.
|
||||
|
||||
Passive comparison keeps lookup identity, cross-capture correspondence, content
|
||||
evidence, and inventory coverage separate:
|
||||
|
||||
| Observation | Comparison outcome |
|
||||
| ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
|
||||
| Renamed WebMCP tool keys/frame IDs with one matching name, owner origin, and frame URL | Compare the registration content; local IDs do not prove change |
|
||||
| Duplicate WebMCP owners with the same name, origin, and frame URL | Unknown correspondence; complete group count differences still prove change |
|
||||
| Matching script inventory keys with retained source digests | Compare the retained SHA-256 values even without a producer hash |
|
||||
| One corresponding script source is unavailable, or neither source nor producer hash is available | Source equality remains unknown; inventory changes and other proven differences survive |
|
||||
| A partial HTTP response group is a subset of the complete peer | Unknown; omitted repeated responses can explain the difference |
|
||||
| An observed HTTP response fingerprint is absent from the complete peer group | Changed; omissions cannot explain that retained response |
|
||||
| A WebSocket connection or frame inventory is incomplete | Do not align retained payloads by position |
|
||||
|
||||
Storage fingerprints decode supported CDP primitive/JSON values before hashing.
|
||||
Debugger descriptions, previews, and remote references do not represent storage
|
||||
content. Actual JSON properties with those names remain content. Reference-only
|
||||
objects, unsupported values, and opaque cookie partition identities remain
|
||||
incomplete. Previously exported fingerprints are not recomputed; recapture both
|
||||
sides when comparing captures produced across this decoder change.
|
||||
|
||||
- `capture_web_screenshot` / `rea capture-web-screenshot` returns a content-addressed visible-viewport PNG.
|
||||
- `compare_web_screenshots` / `rea compare-web-screenshots` performs bounded local PNG pixel comparison without OCR or external services.
|
||||
- The CLI comparison commands accept each capture, screenshot artifact or normalization policy as inline JSON or a JSON file path. Use files for screenshot artifacts and scenario captures, whose embedded PNG bytes can exceed the host's command-line length limit.
|
||||
@@ -320,8 +347,18 @@ Cancellation and clock-request failures retain their own outcomes.
|
||||
## Data minimization
|
||||
|
||||
The Link projection parses repeated CDP header field lines independently and
|
||||
retains their declarations in order, including derived untrusted agent hints.
|
||||
Commas inside URI targets or quoted parameters remain part of those values.
|
||||
retains their declarations in order. Each link keeps its target in `href` and
|
||||
its relationship context in `context_url` with a separate `context_scope`;
|
||||
absent `anchor` uses the response URL, while a relative `anchor` resolves
|
||||
against that URL. Anchored links remain in the projection, but a `link_rel`
|
||||
agent hint is emitted only when the resolved context matches the response URL
|
||||
before userinfo credentials are removed. Following [RFC 8288](https://www.rfc-editor.org/rfc/rfc8288.html),
|
||||
the `rel`, `anchor`, and `type` parameters use their first occurrence, and
|
||||
quoted-pair escapes are decoded as specified by [RFC 9110 §5.6.4](https://www.rfc-editor.org/rfc/rfc9110.html#section-5.6.4).
|
||||
The context fields are optional when reading older saved captures. Commas
|
||||
inside URI targets or quoted parameters remain part of those values.
|
||||
Well-known-resource hints require an exact supported pathname; path case is
|
||||
preserved because a case variant may identify a different HTTP resource.
|
||||
COOP and COEP projections retain the exact declared token after validating the
|
||||
complete Structured Field Item, including parameters such as `report-to`.
|
||||
These are declarations, not an assessment of the document's effective policy;
|
||||
@@ -331,15 +368,16 @@ REA retains local observation data and removes only URL userinfo credentials, ex
|
||||
|
||||
- URL observations preserve the complete local URL, including query values, fragments, duplicate parameters, and their order. Only username/password userinfo is removed; malformed original URL strings remain available with `origin: null`.
|
||||
- DOM snapshots retain node types, node names, value lengths, and attribute names, but not text or attribute values.
|
||||
- Accessibility structure and roles are retained by default, while names and descriptions require `include_accessibility_text: true`.
|
||||
- Supported DOM URL attributes are projected separately as resolved destinations. Empty `action` on HTML or XHTML forms and empty `formaction` on HTML or XHTML submit controls resolve to the document URL; other relative URL attributes resolve against the captured document base.
|
||||
- Accessibility structure and reported roles are retained by default, while names and descriptions require `include_accessibility_text: true`. The browser protocol may omit an individual role; that role remains unknown for comparison. Other observed accessibility differences can still establish a change.
|
||||
- Network observations retain method, status, MIME type, size, type, initiator stack location, and complete URLs with userinfo credentials removed. Redirects reported by CDP are attached as ordered `redirects` on the one request ID, with the prior request URL, CDP response URL, method/type, response status/MIME/encoded length, request timestamp, and the next `requestWillBeSent` event timestamp. CDP delivers `redirectResponse` with that next request event, so the latter is an event boundary rather than an exact response timestamp. Redirect response headers and bodies are discarded; hops outside the selected origins are discarded with the request chain. Headers are discarded after an allowlisted projection of length/encoding, structured CSP/Link/policy fields, and untrusted agent hints. Cookies and authorization headers are never retained.
|
||||
- Request/response bodies are not requested or parsed by default. When selected, only allowed-origin JSON media types are read, converted immediately to complete value-free typed paths, types and observation counts, and discarded. Each path segment is either `{ "kind": "property", "name": "raw property name" }` or `{ "kind": "array-element" }`; array-element types include primitives and nested arrays. Literal `*` properties remain distinct from array elements. `Network.getResponseBody` is never sent unless JSON body shape capture is selected. Comparison uses body shapes only when both captures selected them, and compares request/response shapes only where both observations provide those facts. Unavailable or truncated selected coverage makes equivalence unknown; observed differences still report changed.
|
||||
- Request/response bodies are not requested or parsed by default. When selected, only allowed-origin JSON media types are read, converted immediately to complete value-free typed paths, types and observation counts, and discarded. Each path segment is either `{ "kind": "property", "name": "raw property name" }` or `{ "kind": "array-element" }`; array-element types include primitives and nested arrays. Literal `*` properties remain distinct from array elements. `Network.getResponseBody` is never sent unless JSON body shape capture is selected. A JSON-typed request body that CDP reports through `hasPostData` but omits from `postData`, or that cannot be parsed as JSON, makes `json_body_shapes` unavailable. That request's `body_shapes.status` is `partial`, not `included`, when only its response shape was captured. Comparison uses body shapes only when both captures selected them, and compares request/response shapes only where both observations provide those facts. Unavailable or truncated selected coverage makes equivalence unknown; observed differences still report changed.
|
||||
For normalized passive inputs with complete request inventories on both sides,
|
||||
request additions and removals remain observable even when selected body shapes,
|
||||
response metadata, or WebSocket coverage are unavailable. HTTP request and
|
||||
WebSocket inventory coverage are evaluated separately; complete HTTP coverage
|
||||
cannot prove a missing WebSocket connection. Limited request inventory still
|
||||
prevents request-absence claims. This comparison rule does not make live CDP's
|
||||
cannot prove a missing WebSocket connection. A missing request in a limited inventory cannot prove absence; a retained
|
||||
request absent from a complete peer can prove a change. This comparison rule does not make live CDP's
|
||||
attach-limited inventory complete or establish body-shape equality.
|
||||
An unavailable HTTP resource type also leaves request identity incomplete:
|
||||
observations with the same method and URL remain possible matches across types,
|
||||
@@ -354,11 +392,15 @@ REA retains local observation data and removes only URL userinfo credentials, ex
|
||||
uses `websocket_connections` and `websocket_frames`. Drops in other event kinds
|
||||
and the aggregate total do not by themselves limit HTTP inventory. Proven
|
||||
modifications remain reportable despite incomplete inventory.
|
||||
Repeated identical HTTP content samples establish multiplicity changes only
|
||||
with complete request inventories; limited inventories retain known content
|
||||
comparisons without interpreting duplicate sample counts as changes.
|
||||
Repeated HTTP samples retain multiplicity. A partial group that is contained
|
||||
in a complete peer cannot prove modification, even when the omitted response
|
||||
had different content. A retained sample absent from the complete peer can
|
||||
prove modification. Two partial groups cannot establish response
|
||||
correspondence from their different retained samples alone.
|
||||
WebSocket stream inventories and connection counts likewise require complete
|
||||
WebSocket coverage. Redirect resource types use only shared known metadata:
|
||||
WebSocket coverage. Retained frame positions are compared only with complete
|
||||
connection/frame inventories; matching direction/opcode sequences alone do
|
||||
not prove alignment after drops. Redirect resource types use only shared known metadata:
|
||||
an omitted type leaves equality unknown rather than proving a modification.
|
||||
- Console observations with a stack source retain call type, argument types, the CDP `Runtime.Timestamp` in milliseconds since Unix epoch, and source location. An absent or invalid timestamp is `null` and makes `console_events` incomplete; an observed zero remains zero. Argument types are listed by CDP argument position. An absent or non-array argument inventory is `null`, and a malformed argument keeps its position as `unknown`; either makes `console_events` incomplete, while an observed empty inventory remains `[]`. A malformed stack or top stack frame is not replaced by its caller: the console event is excluded, and a request initiator location or WebMCP `registration_source` is `null`; each is reported as `invalid_protocol_value`. This epoch-millisecond clock is separate from the monotonic-second timestamps in `observe-web-session`. When console text capture is selected, already-delivered primitive values are retained verbatim with their original `argument_index`; objects, getters, and remote properties are never expanded. Text capture is `unavailable` when the argument inventory is unknown.
|
||||
- WebSocket observations retain direction, opcode, and payload byte length. A missing or malformed CDP opcode is returned as `null`, with opcode-dependent payload byte length and shape also `null`, and marks `websocket_frames` incomplete. Missing or wrong-typed payload data is not treated as empty; its byte length is `null`, and a text payload shape is unknown. Numeric opcode `0` and an observed empty payload remain distinct from missing data. Opcode is nullable in the public inspection schema, so clients must handle unknown protocol values. When shape capture is selected, text messages are classified as text or complete value-free JSON shape; binary bytes, hashes, prefixes, and raw payloads are never retained.
|
||||
@@ -384,8 +426,17 @@ validation and resource bounds. Omitted script metadata makes its affected
|
||||
section explicitly truncated.
|
||||
Disallowed-origin entries are filtered before retention.
|
||||
|
||||
Script metadata and selected source reads use one fixed admitted-script snapshot.
|
||||
New in-scope script IDs still retained when the final CDP read completes are
|
||||
counted in `scripts.total` and `completeness.dropped_events.scripts`, with
|
||||
`scripts` marked truncated; they do not extend the source-read pass. Repeated
|
||||
late events for the same ID count once. The original snapshot is not replaced
|
||||
or reduced by later updates to an existing ID. These omissions do not imply
|
||||
that a source byte or time budget was exhausted.
|
||||
|
||||
Selected script-source collection shares a 32 MiB aggregate UTF-8 retention
|
||||
budget and a 20-second deadline across the capture. An oversized source is
|
||||
budget and the `command_timeout_ms` deadline (default 20000 ms) across the
|
||||
capture. The byte budget has no runtime override. An oversized source is
|
||||
omitted while later smaller sources may still fit. When the deadline expires,
|
||||
remaining source reads are skipped. Script metadata, per-item omission reasons,
|
||||
and `script_sources` completeness remain available. A single CDP response can
|
||||
@@ -393,19 +444,25 @@ still be materialized up to the separate 64 MiB transport limit before source
|
||||
admission; the retention budget does not bound that transient allocation.
|
||||
|
||||
Bundle parsing and semantic inspection run sequentially in an owned child,
|
||||
without executing captured code. `max_heap_mb` defaults to 1024 MiB V8
|
||||
old-space; `analysis_timeout_ms` defaults to 30000 per script, including startup
|
||||
and transfer. A failed or timed-out script becomes an explicit unknown while
|
||||
completed findings and later scripts remain available. `total_analysis_timeout_ms`
|
||||
defaults to 300000 across script analysis; expiry returns a typed timeout with
|
||||
partial Evidence and identifies unstarted scripts. These controls are also
|
||||
available as CLI flags with hyphenated names. Capture and optional source-map
|
||||
fetching have separate budgets.
|
||||
without executing captured code. These are separate phases. `max_heap_mb`
|
||||
defaults to 1024 MiB V8 old-space (range 128..16384). `analysis_timeout_ms`
|
||||
defaults to 30000 per script, including startup and transfer.
|
||||
`total_analysis_timeout_ms` defaults to 300000 across script analysis. A
|
||||
per-script deadline above the effective total is rejected. A failed or
|
||||
timed-out script becomes an explicit unknown while completed findings and later
|
||||
scripts remain available. Total-deadline expiry returns a typed timeout with
|
||||
partial Evidence and identifies unstarted scripts. `source_map_fetch_timeout_ms`
|
||||
defaults to 30000 and is an item limitation, not that analysis timeout. These
|
||||
controls are also available as CLI flags with hyphenated names. Worker protocol
|
||||
and result byte budgets have no runtime override.
|
||||
|
||||
One web-bundle capture/analysis is admitted per REA process at a time. Completed
|
||||
script results share an 8 MiB serialized transfer budget, with host heap
|
||||
reservation checked before decoding and validating another result.
|
||||
Exhausted result capacity stops further script launches and returns a typed
|
||||
When the host reservation is what reaches zero, the failure names that heap
|
||||
headroom and the remaining fixed budget. When the 8 MiB allowance itself is
|
||||
exhausted, the failure names that fixed budget and says it has no runtime
|
||||
override. Either stop ends further script launches and returns a typed
|
||||
resource failure with completed facts and explicit unstarted-script unknowns.
|
||||
Worker control frames are limited to 64 KiB. Cleanup must confirm child termination
|
||||
before releasing its private files; failed cleanup retains its exact owner and
|
||||
@@ -415,8 +472,10 @@ facts, including cancellation during final cleanup.
|
||||
The worker heap setting is not a process-family RSS limit. Node enforces V8
|
||||
old-space flags; Bun ignores them. Windows Bun instead uses an owned process
|
||||
commit limit with a 512 MiB runtime reserve; other Bun hosts have no enforced
|
||||
memory limit. These bounds do not establish an aggregate host-memory limit
|
||||
across other REA operations or external processes.
|
||||
memory limit. An allocation failure before that Windows limit is reported as
|
||||
reached still names the configured limit and says it was not reached. These
|
||||
bounds do not establish an aggregate host-memory limit across other REA
|
||||
operations or external processes.
|
||||
|
||||
Resource-tree inventories distinguish a valid empty `resources` array from a
|
||||
missing or malformed collection. Invalid resource entries are omitted with
|
||||
@@ -429,13 +488,31 @@ An explicitly empty MIME type is valid. The optional content size may be absent;
|
||||
an invalid supplied size remains unknown with incomplete resource coverage while
|
||||
the resource's other facts are retained. Zero and nonnegative fractional sizes
|
||||
are preserved.
|
||||
`resource_key` remains the exact observation identity used by script
|
||||
reconciliation. Capture comparison groups resources by URL, origin, type and
|
||||
MIME type, then compares known sizes within a group. If a matched group contains
|
||||
an unknown size, comparison reports unknown rather than treating the observation
|
||||
as a resource addition or removal; complete inventory coverage still establishes
|
||||
when an entire group is absent.
|
||||
|
||||
CDP discovery has a 10-second deadline. Each WebSocket handshake and command
|
||||
response has its own 20-second deadline, separate from the caller-selected
|
||||
observation window. A stalled handshake or command reports `provider_timeout`;
|
||||
caller cancellation still reports cancellation. WebSocket messages remain subject
|
||||
to the [64 MiB limit](#request-boundary). REA does not impose a message-count or
|
||||
pending-command quota. On cancellation, it closes only its own WebSocket,
|
||||
CDP discovery has a 10-second response deadline. HTTP discovery documents
|
||||
use an 8 MiB budget. Browser-socket discovery (`Browser.getVersion`,
|
||||
`Target.getTargets`) uses the 64 MiB protocol message budget. Neither budget
|
||||
nor the discovery deadline has a runtime override. `list_browser_targets` accepts no
|
||||
`command_timeout_ms`: HTTP discovery and browser-socket discovery
|
||||
(`Browser.getVersion`, `Target.getTargets`) stay on that fixed deadline, and
|
||||
the socket closes without a later command. Other CDP tools use
|
||||
`command_timeout_ms` (default 20000) for each WebSocket handshake and command
|
||||
response, separate from the caller-selected observation window, discovery, and
|
||||
the 5000 ms cleanup grace. A browser-level socket's handshake and the following
|
||||
`Target.attachToTarget` each receive that full deadline; they do not share one
|
||||
budget. A stalled handshake or command reports
|
||||
`provider_timeout` and names `command_timeout_ms` only when that operation
|
||||
accepts it; caller cancellation still reports cancellation. WebSocket messages
|
||||
remain subject to the [64 MiB limit](#request-boundary), which has no runtime
|
||||
override. REA does
|
||||
not impose a message-count or pending-command quota. On cancellation, it closes
|
||||
only its own WebSocket,
|
||||
waiting up to one second before terminating it. Malformed unsolicited events
|
||||
and malformed replies to pending commands poison the connection so later
|
||||
commands fail closed. A correlated reply's session ID must match the command's
|
||||
@@ -444,7 +521,7 @@ rejects it as unknown; other command rejections retain their reported failure.
|
||||
|
||||
Network and console coverage starts only after REA attaches and enables the relevant CDP domains. `prior_activity_available` is always `false`; absence from these arrays is not evidence that an event never occurred. Scripts are different: scripts the page parsed before REA attached are still reported under `scripts`. A page that loaded before attach can therefore list its scripts while `network.requests` lacks the requests that fetched them. If CDP reuses a request ID without supplying redirect metadata, REA retains the predecessor observation and marks network coverage incomplete.
|
||||
|
||||
Source maps are not fetched by inspection. Bundle analysis fetches them only when `fetch_source_maps` is selected, with exact-origin redirect checks and no credentials, cookies, or referrer. Each fetch operation has a 30-second deadline and a 64 MiB aggregate streamed-response budget across redirects. A deadline or byte-limit failure remains explicitly unavailable and makes bundle completeness partial. Source-map decoding also bounds raw resolved identities to 64 MiB and aggregate inline evidence to 32 MiB. Failed maps preserve their failure context when it fits; if another context cannot fit, collection stops with the full requested count, the returned processed count, and an explicit unknown-results limitation. Retained mappings and original sources are returned inline. See [source-location limits](web-source-location.md) for the structural decoder bounds. Original source artifacts with `.ts`, `.tsx`, `.mts`, or `.cts` suffixes carry `text/typescript`; other source names retain `text/javascript`.
|
||||
Source maps are not fetched by inspection. Bundle analysis fetches them only when `fetch_source_maps` is selected, with exact-origin redirect checks and no credentials, cookies, or referrer. Each fetch operation uses `source_map_fetch_timeout_ms` (default 30000) and a 64 MiB aggregate streamed-response budget across redirects. The byte budget has no runtime override. A fetch overrun is an item limitation, not a thrown analysis timeout. A deadline or byte-limit failure remains explicitly unavailable and makes bundle completeness partial. Source-map decoding also bounds raw resolved identities to 64 MiB and aggregate inline evidence to 32 MiB. Failed maps preserve their failure context when it fits; if another context cannot fit, collection stops with the full requested count, the returned processed count, and an explicit unknown-results limitation. Retained mappings and original sources are returned inline. See [source-location limits](web-source-location.md) for the structural decoder bounds. Original source artifacts with `.ts`, `.tsx`, `.mts`, or `.cts` suffixes carry `text/typescript`; other source names retain `text/javascript`.
|
||||
|
||||
source-map items retain the script's `declared_url` separately from the observed
|
||||
`effective_url`. successful maps use the latter as their source-resolution base.
|
||||
@@ -456,6 +533,10 @@ Current fetches emit a string or null; historical observations may omit
|
||||
An observed URL must fit before its response body is read. If it cannot fit,
|
||||
remaining map results are explicitly unknown; failed cancellation retains its
|
||||
cleanup context and resource constraint.
|
||||
Indexed maps whose decoded mappings cross the next section's starting position
|
||||
are invalid under [ECMA-426](https://tc39.es/ecma426/2024/), rather than complete
|
||||
maps with clipped mapping rows. Fetch collection and source tracing share this
|
||||
validation.
|
||||
|
||||
## Non-goals and threat model
|
||||
|
||||
|
||||
@@ -23,9 +23,21 @@ that rejection does not roll back browser effects. REA removes its owned
|
||||
future-document scripts, restores live frame methods, then disconnects.
|
||||
Add secret declarations, storage seeds, and additional artifact or event
|
||||
capture only when needed. Action, secret, and storage counts are not capped.
|
||||
Duration, action, and navigation timeouts remain fixed provider-owned liveness
|
||||
limits. `capture.limits` controls retained event and network-content budgets;
|
||||
it does not change those liveness deadlines.
|
||||
Duration, action, and navigation timeouts remain separate from CDP command
|
||||
deadlines. `command_timeout_ms` (default 20000; omit it to keep that default
|
||||
and leave it out of Evidence) bounds launch startup, the connect-over-CDP
|
||||
handshake, target lookup, environment commands, and storage CDP commands,
|
||||
including replies from attached child targets. Set it in the scenario JSON.
|
||||
`capture-browser-scenario` has no `--command-timeout-ms` option.
|
||||
It does not change action `timeout_ms`, `wait_for_timeout.duration_ms`, or
|
||||
navigation. Service-worker restoration keeps a fixed 5000 ms grace and does
|
||||
not inherit a raised `command_timeout_ms`. CDP discovery stays on its own
|
||||
fixed deadline. When service workers are blocked, the registration check
|
||||
before discovery has its own fixed 10000 ms deadline; `command_timeout_ms`
|
||||
does not apply because discovery has not started. The discovery deadline
|
||||
covers endpoint discovery only. The following WebSocket handshake and
|
||||
`Target.attachToTarget` each use `command_timeout_ms`. `capture.limits` controls retained event and network-content
|
||||
budgets; it does not change those liveness deadlines.
|
||||
|
||||
## Minimal launch example
|
||||
|
||||
@@ -375,6 +387,24 @@ observed) and excludes the sequence reference from normalization.
|
||||
Playwright scenario capture does not supply initiator stacks; passive CDP
|
||||
observation retains its own initiator evidence.
|
||||
|
||||
## Storage value fingerprints
|
||||
|
||||
New storage snapshots include `fingerprint_version: 2`. Non-secret, well-formed
|
||||
JavaScript strings retain their SHA-256 over UTF-8. Strings with unpaired UTF-16
|
||||
surrogates use SHA-256 over a raw `0xff` byte followed by their exact UTF-16LE
|
||||
code units; this prefix cannot occur in UTF-8. Declared secrets remain
|
||||
`redacted-secret` with a null digest, without a second or legacy digest.
|
||||
|
||||
A missing version identifies legacy UTF-8 fingerprints, which replaced unpaired
|
||||
surrogates and cannot establish value identity. Storage containing any legacy
|
||||
hashed value is conservatively compared as `unknown`, including old-to-old
|
||||
comparisons; recapture both sides to compare reliably. This also conservatively
|
||||
withholds some otherwise provable legacy differences. Empty or entirely
|
||||
secret-redacted storage keeps its existing comparison semantics. The version is
|
||||
checked before normalization and excluded from content comparison: changing
|
||||
encoding metadata alone does not establish a website change. Existing captures
|
||||
and their completeness records are not rewritten.
|
||||
|
||||
## Scenario comparison
|
||||
|
||||
`compare_web_captures` and `compare-web-captures` also accept two complete
|
||||
@@ -407,6 +437,15 @@ sorted canonically before application, making the same policy reproducible
|
||||
regardless of input order. Rules operate only on already-redacted durable
|
||||
capture fields and are preserved in the result.
|
||||
|
||||
Cookies, local storage, and session storage are compared as unordered inventories
|
||||
after caller literal rules apply. Enumeration order alone does not establish a
|
||||
storage change. Canonical ordering uses the complete entry, preserving cookie
|
||||
scope/flags, value fingerprints, and duplicate entries even when redaction or
|
||||
literal rules make names collide. Captured storage arrays retain their original
|
||||
order. The `compare_storage_entries_as_unordered_collection` built-in rule
|
||||
participates in the normalization commitment; new storage comparison digests
|
||||
therefore differ from earlier order-sensitive comparisons.
|
||||
|
||||
Each aligned step reports changed, unchanged, or unknown. Changed and unknown
|
||||
action, screenshot, DOM, accessibility, URL, history, storage, and event
|
||||
artifacts carry their normalized before/after digests and capture states.
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# Static analysis in GitHub Actions
|
||||
|
||||
The [minimal workflow](https://github.com/morluto/rea/blob/main/examples/github-actions/rea-analysis.yml) builds a small
|
||||
JavaScript application, analyzes its files without executing them, and uploads
|
||||
machine-readable results. It uses the existing CLI, not a separate GitHub Action
|
||||
or an MCP client. It does not promise support for every REA provider.
|
||||
|
||||
## Run the example
|
||||
|
||||
1. Copy the example to `.github/workflows/rea-analysis.yml` in your repository and
|
||||
commit it to the default branch. No existing application or package manifest is
|
||||
needed for the self-contained demonstration.
|
||||
2. Enable GitHub Actions if necessary. Select **REA static analysis example** in
|
||||
the Actions tab and choose **Run workflow**.
|
||||
3. Download the `rea-analysis` artifact after the run. Its files are:
|
||||
|
||||
| File | Meaning |
|
||||
| ----------------- | -------------------------------------------------------------------------------------------------- |
|
||||
| `analysis.json` | Original CLI JSON, including complete Evidence on success or the error report when one is emitted. |
|
||||
| `analysis.stderr` | Original diagnostics/progress; an empty file is normal when there are none. |
|
||||
| `exit-code.txt` | Original analysis process exit code. |
|
||||
|
||||
The example pins Node.js 24.22.1, REA 6.7.0, and action commit revisions. It installs
|
||||
REA into the runner's temporary directory rather than changing the application's
|
||||
dependencies. This pins the tool version, not every transitive npm dependency;
|
||||
use a reviewed, committed package lock and `npm ci` if your integration requires
|
||||
that stronger dependency-reproducibility guarantee.
|
||||
|
||||
## Prerequisites and trust
|
||||
|
||||
The runner is GitHub-hosted Ubuntu 24.04 with Bash, npm, and `ps` from `procps`.
|
||||
Other Linux images must supply `procps`; REA's supervised process controls use it.
|
||||
This static JavaScript operation needs no Hopper, Ghidra, IDA, Java, browser,
|
||||
Docker, GPU, external API key, or user-supplied GitHub secret. The workflow only
|
||||
requests `contents: read`; artifact upload uses the runner's normal Actions
|
||||
credentials.
|
||||
|
||||
Replace **Build a known artifact** with your reviewed build, and set
|
||||
`ARTIFACT_PATH` to its application directory (relative to the checkout) or an ASAR.
|
||||
The demonstration creates its own tiny application; it deliberately throws if
|
||||
executed. REA reads it statically. Your replacement build itself can execute code:
|
||||
review it separately and do not add untrusted pull-request builds to a privileged
|
||||
`pull_request_target` workflow. The example is manually triggered, not an
|
||||
untrusted-PR execution policy.
|
||||
|
||||
Reports can contain paths, URLs, source-derived facts, and caller-selected data.
|
||||
Only analyze artifacts and publish reports you are authorized to share. Do not
|
||||
rely on REA inferring secrets from their names. Review artifact access and
|
||||
retention for your repository; the example retains reports for seven days.
|
||||
|
||||
## Failure, partial results, and unsupported capabilities
|
||||
|
||||
The analysis step captures stdout and stderr separately, records `$?`, and exits
|
||||
with that same status. There is no `continue-on-error`, `|| true`, output filter,
|
||||
or pipeline that could turn a failed analysis green. Before checkout or other
|
||||
fallible steps, the workflow creates a fresh report directory under `RUNNER_TEMP`.
|
||||
Analysis and upload both use that directory, never a checked-in `reports/rea` or
|
||||
other workspace files. The upload step uses `always()` when that directory was
|
||||
prepared, so available diagnostics survive an analysis failure. If installation
|
||||
or the build failed before analysis began, it is empty and upload warns rather
|
||||
than publishing stale results or inventing a successful result. Runner loss or
|
||||
cancellation can still prevent upload.
|
||||
|
||||
`--json --full-output` selects a machine-readable envelope; it does **not** mean
|
||||
that analysis was complete. A successful operation can retain partial analysis,
|
||||
unknowns, and limitations. Exit zero is not a security verdict, proof of complete
|
||||
coverage, or a policy gate for those findings. Inspect the saved Evidence and
|
||||
coverage before making such a decision. See [output and exit status](cli.md#output-and-exit-status).
|
||||
|
||||
A nonzero exit can represent invalid input, unavailable tooling, an unsupported
|
||||
host/capability, or another operation failure. Keep the original JSON error (when
|
||||
emitted), stderr, and exit code, and use their category/message to diagnose it.
|
||||
An early startup failure may leave `analysis.json` empty; do not parse that as
|
||||
successful analysis. Select a supported operation or explicitly provision its
|
||||
[documented prerequisites](installation.md); do not silently switch providers,
|
||||
execute the artifact, or ignore the failure to obtain a green job.
|
||||
|
||||
To exercise the failure path, temporarily set `ARTIFACT_PATH` to
|
||||
`build/missing-artifact` without changing the demo build. Analysis must fail,
|
||||
`exit-code.txt` must be nonzero, and the available reports must still upload.
|
||||
To exercise unsupported input, set `ARTIFACT_PATH` to `build/rea-ci-demo/index.js`:
|
||||
this operation accepts an application directory or ASAR, not a single source file.
|
||||
The retained JSON error has category `unsupported_target`; the step exits nonzero.
|
||||
Restore the correct path before using the example normally.
|
||||
|
||||
To exercise partial analysis, append `export const broken = ;` to the demo's
|
||||
JavaScript. REA 6.7.0 retains `data.normalized_result.statistics.parse_failures`
|
||||
and an incomplete-coverage limitation while the operation can still exit zero.
|
||||
Inspect those facts instead of treating process success as full coverage. The
|
||||
report JSON and diagnostics remain unfiltered in all three cases.
|
||||
+289
-5
@@ -3,6 +3,8 @@
|
||||
Use the CLI for a direct inspection or a script. It uses the same application
|
||||
workflows and evidence contracts as REA's MCP server. Each CLI invocation is a
|
||||
separate process; save results when you want to use them in a later command.
|
||||
For a pinned, noninteractive workflow with retained reports, see
|
||||
[static analysis in GitHub Actions](ci-analysis.md).
|
||||
|
||||
## Run a command
|
||||
|
||||
@@ -44,6 +46,119 @@ module page. See
|
||||
[JavaScript application workflows](javascript-application-workflows.md) for
|
||||
views, feature traces and comparisons that take the same saved Evidence.
|
||||
|
||||
## JSON Lines record output
|
||||
|
||||
Use `--format jsonl` to consume row-oriented results one record per line:
|
||||
|
||||
```bash
|
||||
cat > observations-view.json <<'JSON'
|
||||
{"source":{"kind":"evidence-file","path":"app-evidence.json"},"view":{"kind":"javascript-facts","property_keys":[],"offset":0,"limit":32}}
|
||||
JSON
|
||||
rea inspect-analysis-view observations-view.json --format jsonl > observations.jsonl
|
||||
```
|
||||
|
||||
This request selects up to 32 observation identities and their provenance,
|
||||
without observation property values.
|
||||
|
||||
This changes JSONL object-collection framing. Scripts that need one complete
|
||||
report or a scalar field should use `--format json`. For a full application
|
||||
graph, first project a supported analysis view rather than selecting an
|
||||
arbitrary nested graph array.
|
||||
|
||||
A top-level array emits its elements in source order. An object must have one
|
||||
clear `rows`, `items`, `records`, or `occurrences` array, directly or under
|
||||
`page`. Evidence uses the same boundaries inside `normalized_result`.
|
||||
An arbitrary report or a scalar selection is refused with an actionable error;
|
||||
use `--format json` for a complete document. If several collections exist,
|
||||
select one with `--filter-output`, for example `normalized_result.rows`.
|
||||
|
||||
Object collections finish with a control record:
|
||||
|
||||
```json
|
||||
{
|
||||
"$rea": "jsonl/v1",
|
||||
"type": "metadata",
|
||||
"records": {
|
||||
"path": ["normalized_result", "rows"],
|
||||
"emitted": 2,
|
||||
"source": 10,
|
||||
"filter": "normalized_result.rows[0,2]"
|
||||
},
|
||||
"context": {
|
||||
"evidence_id": "ev_…",
|
||||
"normalized_result": {
|
||||
"coverage": {
|
||||
"status": "page",
|
||||
"examined": 10,
|
||||
"total": 100,
|
||||
"next_offset": 10,
|
||||
"exhausted": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This abbreviated example illustrates framing. The actual `context` preserves
|
||||
all non-row fields, including Evidence subject, provider, authority, confidence,
|
||||
locations, links, limitations, parent/view digests, pagination and coverage.
|
||||
With `--full-output`, it also retains the command envelope and its metadata.
|
||||
A data filter selects row fields/slices while this context remains available;
|
||||
excluded peer record collections and unselected Evidence `raw_result` are not
|
||||
restored. An explicitly selected `raw_result` remains selected. Retain the
|
||||
original Evidence for complete observations.
|
||||
|
||||
`records.emitted` and `records.source` count the selected output and its source
|
||||
array; they do not assert analysis completeness. Source coverage and unknowns
|
||||
retain their original meaning. Existing row identities and indices remain
|
||||
unchanged unless your field selection excludes them. Empty object collections
|
||||
still emit metadata; an empty top-level array emits no lines. Bare top-level
|
||||
arrays have no synthetic coverage record.
|
||||
|
||||
Command and output-validation failures emit `{"$rea":"jsonl/v1","type":"error","ok":false,"result":…}`
|
||||
and retain the original diagnostic payload. SDK validation/sentinel errors use
|
||||
the SDK's exit status rather than guessing from data fields. `$rea` is reserved
|
||||
at the top level of a data record, so control records are unambiguous; collisions
|
||||
are refused before rows are written. Nested `$rea` values are ordinary data.
|
||||
A missing final metadata record or nonzero exit can indicate an interrupted
|
||||
export; do not treat already emitted rows as a complete result.
|
||||
|
||||
`--token-count` estimates this exact representation, including metadata, one
|
||||
line at a time. Errors remain error records even with token counting enabled.
|
||||
Token windows cannot preserve JSON Lines and are rejected. JSON encoding and
|
||||
stdout writes are incremental, including large escaped strings; this is output
|
||||
streaming over a completed result, not incremental analysis. The analysis still
|
||||
needs its normal resources. A single record must fit the runtime string limit
|
||||
for token estimation; remove `--token-count` to stream a larger record.
|
||||
|
||||
Standalone version and MCP doctor diagnostics remain single JSON documents
|
||||
in JSON Lines mode. Incur's streaming generator events and successful sentinel
|
||||
responses retain their SDK protocol. MCP application results and Evidence
|
||||
contracts are unchanged.
|
||||
|
||||
## Shell completion
|
||||
|
||||
The CLI includes optional shell completion. Run `rea completions --help` to
|
||||
see the available shells and their setup commands. For Bash, load the hook
|
||||
into the current shell:
|
||||
|
||||
```bash
|
||||
eval "$(rea completions bash)"
|
||||
```
|
||||
|
||||
The current Bash hook requires support for `complete -o nosort`; macOS's
|
||||
system Bash 3.2 cannot load it. Use a newer Bash for this hook.
|
||||
|
||||
For future interactive non-login Bash sessions, add the command to
|
||||
`~/.bashrc`. Interactive login Bash sessions read the first available file in
|
||||
`~/.bash_profile`, `~/.bash_login`, and `~/.profile`; add the command to the
|
||||
file your shell reads, or have that file source `~/.bashrc`. Remove the command
|
||||
from the startup file to stop loading completion, and run `complete -r rea` to
|
||||
remove the registration from the current shell. These are manual, opt-in
|
||||
steps.
|
||||
Completion is a discovery aid; use `rea COMMAND --help` to confirm the
|
||||
available options and subcommands.
|
||||
|
||||
## Managed assemblies (.NET)
|
||||
|
||||
For a .NET PE/CLI assembly, inspect its identity and deployment form before
|
||||
@@ -63,6 +178,16 @@ or repeat it to select several types.
|
||||
Selection limits decoding to the selected types; member references remain an
|
||||
assembly-wide inventory, so the output can still be large.
|
||||
|
||||
Select `--detail summary --evidence-bundle /absolute/path/members.json` to
|
||||
receive identity, selection, coverage, limitations and collection counts while
|
||||
saving the complete original Evidence in a new bundle. Summary requires that
|
||||
explicit destination; existing files are preserved. Later
|
||||
`inspect-analysis-view` calls can page the exact parent from the saved bundle
|
||||
without reopening the assembly. See
|
||||
[CLI summary and saved member rows](managed-code-analysis.md#cli-summary-and-saved-member-rows)
|
||||
for the complete command sequence. Omitted or `--detail complete` retains the
|
||||
full inline response.
|
||||
|
||||
Choose the workflow from the artifact's contents rather than its `.exe` or
|
||||
`.dll` extension. The managed parser requires PE/CLI metadata; it does not
|
||||
unpack .NET single-file hosts or decode IL2CPP. For the image, type and method
|
||||
@@ -145,6 +270,49 @@ dependency edges, and the section's file range. A missing `.dep-v0` section is
|
||||
null metadata, not proof that the binary has no dependencies. See
|
||||
[Rust binaries](rust-binaries.md).
|
||||
|
||||
Inspect a PE Authenticode certificate table without executing the image or
|
||||
verifying signatures:
|
||||
|
||||
```bash
|
||||
rea inspect-pe-certificates /absolute/path/to/application.exe --json
|
||||
```
|
||||
|
||||
The workflow reports `WIN_CERTIFICATE` entries and, for PKCS#7 signedData,
|
||||
embedded X.509 serial, issuer, subject, and validity fields. A missing security
|
||||
directory is observed absence of that table. See
|
||||
[PE Authenticode certificate tables](pe-certificates.md).
|
||||
|
||||
Inspect ELF PT_NOTE and SHT_NOTE tables without executing the image:
|
||||
|
||||
```bash
|
||||
rea inspect-elf-notes /absolute/path/to/program --json
|
||||
```
|
||||
|
||||
The workflow reports note owners, types, descriptor hashes, and GNU build-id
|
||||
or ABI-tag fields when those descriptors match. A missing note table is
|
||||
observed absence of those declarations. See [ELF note tables](elf-notes.md).
|
||||
|
||||
Inspect a CPython 3.7–3.13 `.pyc` header and nested marshal code objects
|
||||
without executing bytecode or installing Python:
|
||||
|
||||
```bash
|
||||
rea inspect-python-pyc /absolute/path/to/module.pyc --json
|
||||
```
|
||||
|
||||
The workflow reports the pinned CPython version for the magic, PEP 552 hash or
|
||||
mtime/size fields, nested function names, and bytecode SHA-256. Bytecode is
|
||||
not decompiled. See [CPython pyc inspection](python-pyc.md).
|
||||
|
||||
Inspect an Erlang BEAM file without executing bytecode:
|
||||
|
||||
```bash
|
||||
rea inspect-erlang-beam /absolute/path/to/app.beam --json
|
||||
```
|
||||
|
||||
The workflow reports IFF chunk names, atom tables, exports, imports, lambdas,
|
||||
and the Code chunk header. Missing optional tables stay null. See
|
||||
[Erlang BEAM files](erlang-beam.md).
|
||||
|
||||
Configure [Hopper or Ghidra](installation.md#hopper), the
|
||||
[IDA adapter](ida-provider.md), or [Kuna](kuna-provider.md) before analyzing a
|
||||
native target. Substitute
|
||||
@@ -231,7 +399,11 @@ an exact result when the target bytes, operation, parameters, provider and
|
||||
settings match. Mutations and cursor-dependent calls are excluded from the
|
||||
cache. Snapshot files are local and use owner-only permissions.
|
||||
|
||||
Dispatching a metadata write invalidates the active session's snapshot cache,
|
||||
Importing an Evidence bundle refreshes retained subject display names and paths.
|
||||
It preserves cached analysis results, including observations for other targets.
|
||||
Snapshot bindings that use a replaced record retain its updated display path.
|
||||
|
||||
Dispatching a provider metadata write invalidates the active session's snapshot cache,
|
||||
even if its reply fails: the provider may already have applied the write.
|
||||
Close and reopen the target before importing or saving another snapshot.
|
||||
|
||||
@@ -279,7 +451,12 @@ Exports preserve an existing destination unless `--overwrite` is explicit.
|
||||
For application traces and version comparisons, see
|
||||
[JavaScript application workflows](javascript-application-workflows.md).
|
||||
MCP [retained Evidence references](mcp-contracts.md#retained-application-evidence-inputs)
|
||||
belong to one connection. Separate CLI calls consume full saved records.
|
||||
belong to one connection. Separate CLI calls can consume full saved records.
|
||||
`inspect-analysis-view REQUEST.json --evidence-bundle BUNDLE.json` resolves
|
||||
the request's `retained-evidence` source ID from that authenticated bundle,
|
||||
including bundles exported from an MCP session. The same view JSON works for
|
||||
every supported parent kind; no target is reopened and no record is selected
|
||||
by file order. Omit `--evidence-bundle` when the request supplies inline Evidence.
|
||||
|
||||
## Import historical source
|
||||
|
||||
@@ -340,11 +517,33 @@ Entries that change during an import retain an unavailable-entry diagnostic
|
||||
alongside readable siblings. If enumeration of an already admitted root fails,
|
||||
the graph keeps its observed children and records the root failure as a
|
||||
top-level limitation. That partial inventory does not establish absence among
|
||||
unexamined children.
|
||||
unexamined children. POSIX directory-entry bytes that are not valid UTF-8 cannot
|
||||
be represented as graph paths; the containing directory (or root) is marked
|
||||
unsupported, and REA does not access the entry through a replacement-character
|
||||
name. Symlink targets are read as bytes too: a target that is not valid UTF-8
|
||||
is retained as an unreadable symlink with its bytes reported in the limitation,
|
||||
and is never resolved through a replacement-character path. Readable siblings
|
||||
remain inventoried.
|
||||
|
||||
JavaScript and TypeScript import parsing requires valid UTF-8. Malformed source
|
||||
bytes retain their original hashes and sizes with a decoding diagnostic; REA
|
||||
does not infer module targets from replacement characters.
|
||||
does not infer module targets from replacement characters. Exact dynamic-import
|
||||
strings, expression-free templates and runtime-transparent TypeScript wrappers
|
||||
retain their targets; computed imports remain unknown. TypeScript import-equals
|
||||
dependencies remain `requires` relationships whether or not they are exported.
|
||||
|
||||
REA derives historical CommonJS paths only when the selected loader and its
|
||||
base are proven: this includes the exact
|
||||
`createRequire(new URL("./file.cjs", import.meta.url))` form and
|
||||
`require.resolve` with `{ paths: [__dirname] }`. Other custom bases and search
|
||||
options remain partial with unknown resolution and the literal requested
|
||||
specifier. Overwritten resolver methods retain that uncertainty; they are not
|
||||
attributed to Node. `require.main` is a module object, so calling it does not
|
||||
establish a loader reference. These relationships do not establish execution;
|
||||
Node's [`require.resolve`](https://nodejs.org/docs/v24.22.1/api/modules.html#requireresolverequest-options)
|
||||
performs lookup without loading the target. An excluded `package.json`
|
||||
also leaves package-directory selection unknown rather than treating the
|
||||
manifest as absent and applying an `index` fallback.
|
||||
|
||||
Historical-source import requires safe no-follow file opens on Linux or
|
||||
macOS. Native Windows returns `unsupported_host`; use Linux REA inside WSL
|
||||
@@ -399,7 +598,8 @@ evidence file's `evidence_id`; otherwise the command refuses with
|
||||
`invalid_request` before binding. Before binding it derives the
|
||||
`environment-state` view of the capture with the manifest's `template_rules`,
|
||||
as `inspect-analysis-view` would, and serves from it: read tools whose views
|
||||
are state-backed answer from a live state, write tools are not served, and
|
||||
are state-backed answer from a live state, write tools are served only where
|
||||
the capture's later reads confirmed their effect, and
|
||||
`/agentenv` serves `data/reset`, `data/add` and `data/get`. When the state
|
||||
cannot be derived, or its catalog exceeds the discovery reservation, it logs a
|
||||
warning with the error code and message and serves replay; `--replay-only` serves replay without deriving. In replay every
|
||||
@@ -455,6 +655,68 @@ of the serve command's stopped document. See
|
||||
[agent environments](agent-environments.md#export-a-bundle) for the folder
|
||||
layout and what the smoke task checks.
|
||||
|
||||
## Compare an environment with its application
|
||||
|
||||
`rea environment-compare <manifest.json> --evidence <capture.json> --probe <probe.json> [--probe <probe.json> ...]`
|
||||
compares the environment the pair serves with probe captures of the application it came from. Each probe is capture
|
||||
Evidence of one call sequence recorded against the application after a reset; the environment's state is reset before
|
||||
each probe, every request to the application's origin is answered as the served environment answers it, and the
|
||||
answer is compared with the application's after ids are mapped and clocks and generated values are normalised. The command reads files only and
|
||||
makes no network call. It prints the report and exits `0`, or prints a structured `invalid_request` error and exits `1`
|
||||
for the same pair refusals as `environment-serve`, a probe that is not capture Evidence, or a browser probe captured
|
||||
without response bodies, or without the request bodies its writes need. See
|
||||
[agent environments](agent-environments.md#measure-fidelity-against-the-application) for the report.
|
||||
|
||||
```sh
|
||||
rea environment-compare manifest.json --evidence capture.json --probe probe.json --json
|
||||
```
|
||||
|
||||
## Report version and runtime
|
||||
|
||||
`rea --version` prints the package version. Add an output format to get the
|
||||
version with the runtime and platform context that a support request needs:
|
||||
|
||||
Version reports do not initialize analysis providers. Invalid global settings
|
||||
or output options still report their usual errors.
|
||||
|
||||
```bash
|
||||
rea --version --json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "rea-agents",
|
||||
"version": "6.7.0",
|
||||
"runtime": { "id": "node", "version": "24.22.1" },
|
||||
"platform": "linux",
|
||||
"architecture": "x64",
|
||||
"supported_runtime": {
|
||||
"range": "^22.23.4 || ^24.22.1 || >=26.12.1",
|
||||
"satisfied": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Meaning |
|
||||
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------- |
|
||||
| `name`, `version` | Published package name and version; `version` matches plain `--version`. |
|
||||
| `runtime.id` | `node` or `bun`. |
|
||||
| `runtime.version` | Version of that runtime. |
|
||||
| `runtime.node_compatibility_version` | Bun only: the Node.js version it reports compatibility with. |
|
||||
| `platform`, `architecture` | Node.js `process.platform` and `process.arch`, such as `linux` and `x64`. |
|
||||
| `supported_runtime.range` | Supported Node.js range. |
|
||||
| `supported_runtime.satisfied` | Whether this runtime is supported, judged as `rea doctor` judges it; Bun by its Node.js compatibility version. |
|
||||
|
||||
The field names are stable. The report contains no paths, environment values,
|
||||
user or host names, and it starts no provider and reads no target. `--format`
|
||||
selects any CLI output format, such as `--format yaml`. JSON follows the usual
|
||||
rule: indented on a terminal, compact when piped or redirected. `--help` still
|
||||
takes precedence. With other output controls, `--version` keeps its existing
|
||||
behavior: valid controls such as `--filter-output` or `--full-output` print the
|
||||
plain version, and invalid combinations report the usual output-flag error,
|
||||
such as `UNSUPPORTED_OUTPUT_COMBINATION` for `--json` with `--token-limit`. Use
|
||||
`rea doctor` for provider and host readiness.
|
||||
|
||||
## Output and exit status
|
||||
|
||||
`rea mcp doctor --json` checks production MCP startup and reports child logs in
|
||||
@@ -473,10 +735,24 @@ redirected, which keeps large results smaller for agents and scripts; pipe
|
||||
through `jq .` for indented files. Output selection and formatting do not change
|
||||
operation status.
|
||||
|
||||
`--format md` escapes backslashes and pipes in table headers and cells, and
|
||||
renders cell line breaks as `<br>`. These are presentation changes; retained
|
||||
Evidence and JSON output keep the original values. Table widths are measured
|
||||
iteratively, so an admitted row page is not limited by the JavaScript function
|
||||
argument count.
|
||||
|
||||
`--filter-output` selects fields from successful command data. Classified failures
|
||||
retain their complete typed diagnostic projection even when the selector matches
|
||||
a field such as `code` or `message`, or names a missing field. `--full-output`
|
||||
controls whether the outer `{ok, error, meta}` envelope is included.
|
||||
Selected own JSON members, including `__proto__`, remain ordinary output data.
|
||||
|
||||
Sibling array slices that select different fields are combined by original row
|
||||
index and emitted in source order, regardless of selector order. Selecting a
|
||||
whole parent row keeps that row intact and takes precedence over narrower fields
|
||||
selected from the same row. For example, `rows[0,2].name,rows[1,3].version`
|
||||
combines both fields for overlapping rows, while `rows[0,2],rows[1,3].version`
|
||||
retains rows 0 and 1 whole.
|
||||
|
||||
For `cutter-command`, `--json-output` requests command-specific JSON from
|
||||
Cutter when available. This is separate from `--format json`, which selects the
|
||||
@@ -536,6 +812,14 @@ command, objdump, Rizin and GDB, and the agent environment server
|
||||
signal-derived status. This describes the current source routing; it is not a
|
||||
claim that every command or provider runtime has been independently exercised.
|
||||
|
||||
Commands with `--evidence_output` select their delivered view, then publish the
|
||||
complete Evidence bundle atomically. Cancellation before publication leaves no
|
||||
new file. A publication that has committed can win a later cancellation; the
|
||||
`cancelled` result then keeps the written path and byte count under
|
||||
`details.diagnostics.evidence_bundle`. If staging cleanup stays incomplete
|
||||
after commit, the `cleanup_incomplete` error reports the same file as
|
||||
`details.published_path` and `details.bytes`.
|
||||
|
||||
When the reader of piped output closes early, as `rea ... | head` does, the
|
||||
CLI stops writing, prints no error and exits `141` (`128 + 13`, the status of a
|
||||
SIGPIPE-terminated writer). The operation itself may have completed; only its
|
||||
|
||||
@@ -14,6 +14,12 @@ preserving your REA client entry. See the
|
||||
|
||||
## GitHub Copilot CLI
|
||||
|
||||
Setup preserves an existing `tools` selection in the REA registration, including
|
||||
an empty list. New registrations default to `["*"]`. A restricted selection is
|
||||
aligned configuration; doctor does not widen it to expose every REA tool. See
|
||||
[Copilot's MCP configuration](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers)
|
||||
for tool-selection settings.
|
||||
|
||||
For GitHub Copilot CLI 1.0.95, `gpt-4.1` model metadata can block ordinary
|
||||
chat with REA's full input-schema profile before sending a model request
|
||||
(`compaction_static_context_blocked`; [#1554](https://github.com/morluto/rea/issues/1554)).
|
||||
@@ -73,12 +79,17 @@ to rerun it.
|
||||
A process that the MSIX app started, such as a terminal in Claude Desktop's
|
||||
Code tab, sees the package's private files at their `%APPDATA%` paths even
|
||||
though it reports no package identity. Setup compares one of those files at
|
||||
both paths. When it finds that redirected view, the app is running, so setup
|
||||
and uninstall refuse to change Claude Desktop's configuration; rerun them from
|
||||
a terminal that Claude Desktop did not start. If the package has no private
|
||||
file to compare, setup and uninstall cannot rule that out and also refuse; open
|
||||
Claude Desktop once if it has never run, quit it fully, then rerun. Doctor
|
||||
reads the same file from either kind of process.
|
||||
both paths: first one from the package's private `Claude` folder, and when
|
||||
that folder has none (some installations keep writing the real
|
||||
`%APPDATA%\Claude`), one from the package's other private roaming folders,
|
||||
which the package redirects in the same way. When it finds that redirected
|
||||
view, the app is running, so setup and uninstall refuse to change Claude
|
||||
Desktop's configuration; rerun them from a terminal that Claude Desktop did not
|
||||
start. If the package keeps no private roaming file at all, setup and
|
||||
uninstall cannot rule that out and also refuse. With Claude Desktop fully
|
||||
quit, add REA's entry by hand to the file setup names, which is the one the
|
||||
app reads, or remove it from both the private copy and the `%APPDATA%` file.
|
||||
Doctor reads the same file from either kind of process.
|
||||
|
||||
The same process also writes everything under `%APPDATA%` and
|
||||
`%LOCALAPPDATA%` into the package's private storage, where other apps never
|
||||
@@ -243,13 +254,51 @@ standalone CLI check.
|
||||
|
||||
## Codex and Devin
|
||||
|
||||
REA manages its launcher and selected provider settings in the client
|
||||
registration. Codex's server and per-tool approval policies are user choices.
|
||||
Setup patches REA's connection fields in the selected file and retains other
|
||||
server settings, including `default_tools_approval_mode`, nested
|
||||
`[mcp_servers.rea.tools.<name>]` tables, tool allow/deny lists, and unrecognized
|
||||
client settings. Doctor accepts Codex's per-tool policy tables. Known malformed
|
||||
policy values block setup before it writes the configuration or a backup, and
|
||||
the diagnostic identifies the setting to repair. See the
|
||||
[Codex configuration reference](https://developers.openai.com/codex/config-reference/)
|
||||
for the supported policy values.
|
||||
|
||||
| Settings | Setup ownership |
|
||||
| ----------------------------------------- | --------------------------------------------------------------------- |
|
||||
| Launcher, transport and activation | Refreshes the REA stdio connection and enables it. |
|
||||
| Explicit server environment | Preserves configured overrides and merges selected provider settings. |
|
||||
| Codex positive timeouts and client policy | Retains caller choices; adds missing recommended REA timeouts. |
|
||||
| Unrelated or future server settings | Retains their parsed values. |
|
||||
|
||||
Dry-run applies the same policy validation and writes no files. A successful
|
||||
refresh keeps an exact recovery snapshot of the original configuration;
|
||||
repeating setup with the same settings performs no write. Uninstall removes
|
||||
the owned REA entry, including its policy, while retaining other servers and
|
||||
the recovery snapshot. A green registration check establishes known
|
||||
configuration alignment; it does not prove that a particular client or fork
|
||||
successfully exposes every REA tool.
|
||||
|
||||
Codex treats an unset or empty `CODEX_HOME` as `~/.codex`. Its MCP server
|
||||
registration supports `startup_timeout_sec` for connection initialization and
|
||||
`tool_timeout_sec` for each tool call. New REA registrations use a 30-second
|
||||
startup timeout and a tool timeout derived from the known provider
|
||||
allowance plus 120 seconds of operation headroom. This yields 450 seconds for
|
||||
the default Ghidra allowance; an explicit Ghidra startup timeout of 2700
|
||||
seconds yields 2820 seconds. Setup preserves positive caller-selected timeout
|
||||
seconds yields 2820 seconds. That 30-second Codex figure is client guidance.
|
||||
REA's own phase budgets are `REA_MCP_INITIALIZE_BUDGET_MS` (default 15000),
|
||||
`REA_MCP_TOOLS_LIST_BUDGET_MS` (default 5000),
|
||||
`REA_MCP_FIRST_CATALOG_BUDGET_MS` (default 20000), and
|
||||
`REA_MCP_DOCTOR_DEADLINE_MS` (default 30000). Each is a positive decimal
|
||||
integer of milliseconds from 1 to 2147483647. Unset keeps the default.
|
||||
Invalid values fail configuration and name the setting. Setup copies a
|
||||
caller-selected value into the registration, and a change is read from the
|
||||
environment that starts REA, so it needs a restart. Doctor and packaged
|
||||
startup probes name the effective milliseconds, whether they came from the
|
||||
default or the setting, the default, the floor, and the maximum. REA does
|
||||
not enforce Codex's 30 seconds as the doctor deadline. The 120000 ms
|
||||
tool-operation headroom and the 64 KiB doctor stderr cap stay fixed. Setup preserves positive caller-selected timeout
|
||||
values in the REA entry, and doctor reports a non-blocking advisory when a tool
|
||||
timeout is shorter than the known provider allowance. An explicitly selected
|
||||
JEB request budget also contributes to the allowance. A configured IDA
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
# Admission limits and recovery
|
||||
|
||||
How to add a REA-owned admission ceiling, budget, or deadline, and what a caller
|
||||
does when one is hit. This is a design rule, not an inventory. Ceilings that
|
||||
should become settings are tracked in
|
||||
[#6176](https://github.com/morluto/rea/issues/6176). Naming honesty for limit
|
||||
errors is [#5910](https://github.com/morluto/rea/issues/5910).
|
||||
|
||||
## Name a default, then a setting when operators need headroom
|
||||
|
||||
Put the number in a named constant with a unit. Do not leave it as a magic
|
||||
number at the call site.
|
||||
|
||||
When a workload may need more room, add a setting whose unset value is that
|
||||
constant. One module under
|
||||
[`src/config/`](https://github.com/morluto/rea/blob/main/src/config) owns the
|
||||
default, any floor, the maximum, the schema, the parser, and the recovery
|
||||
text. Register that schema on `environmentSchema` in
|
||||
[`environment.ts`](https://github.com/morluto/rea/blob/main/src/config/environment.ts).
|
||||
`parseConfig` calls `parseEnvironment`. Doctor uses that same parser through
|
||||
`nativeAnalysisConfigurationError`, so startup and `rea doctor` accept the
|
||||
same values. Add the name to `SELECTED_REGISTRATION_SETTINGS` so `rea setup`
|
||||
copies it into the client registration. Unset keeps today's behavior. An
|
||||
invalid value is a `ConfigurationError` and projects as `configuration_invalid`.
|
||||
Do not fall back to the default.
|
||||
|
||||
[`REA_REGEX_MATCHING_DEADLINE_MS`](https://github.com/morluto/rea/blob/main/src/config/regexMatchingDeadline.ts)
|
||||
([#6267](https://github.com/morluto/rea/pull/6267)) is the reference. Default
|
||||
5000 ms, floor 1 ms, maximum 2147483647 ms, because Node schedules a longer
|
||||
`setTimeout` delay as 1 ms. Setup copies the setting. A hit says:
|
||||
|
||||
> The effective REA_REGEX_MATCHING_DEADLINE_MS value is 5000 ms (source default; default 5000 ms, floor 1 ms, maximum 2147483647 ms). Set REA_REGEX_MATCHING_DEADLINE_MS in the environment that starts REA to a positive decimal integer from 1 to 2147483647, then restart REA. The worker old-generation heap does not raise this deadline.
|
||||
|
||||
[`REA_MCP_MAX_RESPONSE_BYTES`](https://github.com/morluto/rea/blob/main/src/config/mcpResponseBudget.ts)
|
||||
is the byte-budget shape: a decimal safe integer with a 10 MiB floor
|
||||
(`MINIMUM_RESPONSE_BYTES`), the same shared schema, and no silent fallback. A
|
||||
change needs a REA restart and a matching client receive buffer. It does not
|
||||
raise REA's reserved string limit or Node's string ceiling. The setup
|
||||
allowlist does not copy this setting. A new headroom setting should, following
|
||||
the regex deadline.
|
||||
|
||||
A per-call budget is not an environment setting. JavaScript `max_heap_mb`
|
||||
(CLI `--max-heap-mb`) is an integer from 128 to 16384 MiB, default 1024. It
|
||||
applies on the next analysis, which starts a new worker, and does not restart
|
||||
REA. It does not raise the parent result budget, transfer ceilings, or fixed
|
||||
parser limits.
|
||||
|
||||
Host memory and `NODE_OPTIONS` do not raise a REA admission unless that
|
||||
admission's recovery says so. The JavaScript parent result budget is one that
|
||||
does: its recovery says to set `NODE_OPTIONS` (for example
|
||||
`--max-old-space-size=<MiB>`) on the process that starts REA, then restart
|
||||
that process. `max_heap_mb` does not raise it.
|
||||
|
||||
## Keep a fixed ceiling honest
|
||||
|
||||
If the ceiling must stay fixed, say so in the failure. Name the limit and the
|
||||
effective value, say this release has no runtime override, and name what does
|
||||
not raise it. Do not invent a setting.
|
||||
|
||||
JSON values stop at `MAX_JSON_DEPTH` (1000) in
|
||||
[`jsonValue.ts`](https://github.com/morluto/rea/blob/main/src/domain/jsonValue.ts):
|
||||
"JSON value exceeds maximum nesting depth of 1000. This release has no runtime
|
||||
override."
|
||||
|
||||
## Recovery text
|
||||
|
||||
The string the caller sees includes:
|
||||
|
||||
- the limit or setting name
|
||||
- the effective value and unit
|
||||
- the source (`default` or `setting`)
|
||||
- the default, the maximum, and the floor when the setting has one
|
||||
- the next action, including where to set it ("in the environment that starts REA")
|
||||
- whether a restart is required
|
||||
- what the change does not raise
|
||||
|
||||
Invalid settings never take this path. They are `configuration_invalid`.
|
||||
Doctor reports `runtime-configuration:<setting>` and says to correct it in the
|
||||
shell or the MCP registration, then rerun.
|
||||
|
||||
## What agents do
|
||||
|
||||
Follow `remediation.action`. Change a request field or a `REA_*` setting only
|
||||
when that text recommends the change. Restart only when it says the value is
|
||||
read at startup. A sentence that a control does not raise the limit is not a
|
||||
request to change it.
|
||||
|
||||
- Dropped MCP connection: retry the call once only when it is safe to repeat
|
||||
or known not to have started. If it may already have changed the target, or
|
||||
it fails again, tell the user and ask them to restart the MCP client. Do not
|
||||
start with `rea doctor`
|
||||
([#6353](https://github.com/morluto/rea/pull/6353)).
|
||||
- REA could not start its connection: retry once. If it fails again, tell the
|
||||
user and ask them to restart the MCP client, then run `rea doctor`. Do not
|
||||
retry a startup that returns the same unchanged result: tell the user REA
|
||||
could not start, ask them to restart the MCP client, then run `rea doctor`.
|
||||
- Unexpected process-command failure: do not repeat the command. Tell the user
|
||||
to check the input files, then run `rea doctor`.
|
||||
- `cleanup_incomplete`: the operation is not retryable. Retry that exact
|
||||
cleanup owner, named in `details.resources`, and wait until it confirms
|
||||
release before admitting new work on those resources
|
||||
([#6357](https://github.com/morluto/rea/pull/6357)).
|
||||
- `resource_constraint` for capacity, when `retryable` is true: wait for the
|
||||
active admission to finish, then retry within the reported limits. Do not
|
||||
restart REA to free the slot.
|
||||
- `configuration_invalid`: correct the named setting in the environment that
|
||||
starts REA, then start REA again. Run `rea doctor` for the
|
||||
`runtime-configuration:` check. Re-run `rea setup` for that client when the
|
||||
setting is on the registration allowlist, then reconnect so the new process
|
||||
sees it.
|
||||
- `invalid_request`: correct the reported fields from the current schema or
|
||||
CLI help. Do not repeat the unchanged call.
|
||||
|
||||
A restart is required for an environment setting and for a client still
|
||||
running the previous registration. It is not the first step for a transient
|
||||
MCP drop, a capacity wait, or retained cleanup.
|
||||
|
||||
## Tests
|
||||
|
||||
Lock the unset default, one accepted override, rejected floor, maximum, and
|
||||
syntax, and the recovery sentence through `parseEnvironment` and `parseConfig`.
|
||||
[`regexMatchingDeadline.test.ts`](https://github.com/morluto/rea/blob/main/src/config/regexMatchingDeadline.test.ts)
|
||||
is the pattern. Project the failure and assert `configuration_invalid` for a
|
||||
bad value and the recovery wording for a hit.
|
||||
@@ -97,17 +97,18 @@ same bundle. Export writes only the caller-selected output file.
|
||||
| Unity Mono | A managed assembly below `*_Data/Managed` or `Contents/Resources/Data/Managed` has an exact UnityEngine assembly reference. |
|
||||
| Unity IL2CPP | A recognized IL2CPP metadata magic (with the raw version when complete) coexists with a conventionally named native `GameAssembly.dll`, `GameAssembly.so`, `GameAssembly.dylib` or `libil2cpp.so` image. Build correspondence remains unknown. |
|
||||
| Godot | A `GDPC` header at file start or a validated executable trailer offset. |
|
||||
| GameMaker | A bounded `FORM` container starts with a `GEN8` chunk. |
|
||||
| GameMaker | A bounded `FORM` container starts with a `GEN8` chunk. The scan probes conventional `data.win`, `game.unx`, and `game.ios` data files for that header. |
|
||||
| Unreal | `Content/Paks` path conventions or an IoStore TOC signature; arbitrary `.pak` filenames are insufficient. |
|
||||
| Electron | A `resources/app.asar` or `resources/default_app.asar` path convention; archive validity is unverified. |
|
||||
|
||||
When the four-byte metadata magic is present but version bytes are incomplete,
|
||||
the fact retains `raw_version: null`; it does not offer an IL2CPP metadata
|
||||
inspection probe. A complete magic/version prefix with supported raw version 29,
|
||||
31 or 39 offers an
|
||||
`inspect_il2cpp_metadata` follow-up at its admitted file path, including when no
|
||||
native library was found. This probe does not establish full metadata validity
|
||||
or correspondence to a native binary. See [IL2CPP metadata](il2cpp-metadata.md).
|
||||
inspection probe. A complete magic/version prefix with supported raw version
|
||||
24, 27, 29, 31 or 39 offers an `inspect_il2cpp_metadata` follow-up at its
|
||||
admitted file path, including when no native library was found. This probe does
|
||||
not establish full metadata validity or correspondence to a native binary;
|
||||
version 24 inspection still applies only to supported header layouts. See
|
||||
[IL2CPP metadata](il2cpp-metadata.md).
|
||||
|
||||
Candidates are derived or inferred from these facts and do not prove loading or
|
||||
execution. BepInEx, MelonLoader, Easy Anti-Cheat and BattlEye labels identify
|
||||
|
||||
@@ -70,7 +70,10 @@ DOM node indices retain their snapshot positions. Invalid rows are omitted with
|
||||
completeness diagnostics, so `total_nodes` can exceed the retained node count
|
||||
and a parent index can refer to an omitted source node.
|
||||
|
||||
Script metadata retains its execution-context frame ID when CDP supplies one. The capture also
|
||||
Script metadata retains its execution-context frame ID when CDP supplies one and
|
||||
the observed frame generation is authorized. Frames describe the current inventory;
|
||||
script observations can retain earlier authorized frames that have since detached.
|
||||
The capture also
|
||||
inventories worker, service-worker, and shared-worker targets with
|
||||
validated opener-target and parent-frame IDs. Worker discovery uses passive
|
||||
target metadata; REA does not attach to or execute code in those targets.
|
||||
@@ -245,4 +248,10 @@ application path and capture outcome to the static graph, while frames, scripts,
|
||||
workers, and execution claims remain unavailable until a separate passive runtime
|
||||
capture provides them.
|
||||
|
||||
ASAR observation reads the header through one open file handle, validates its declared lengths against the archive size, and limits encoded JSON headers to 16 MiB before parsing. The header cache also retains at most 16 MiB of encoded headers across eight archives. Oversized headers produce a scope refusal.
|
||||
ASAR observation reads the header through one open file handle and validates its
|
||||
declared lengths against the archive size. Header/index admission is the same
|
||||
budget used by static ASAR reads: 16 MiB / 16777216 bytes by default, or
|
||||
`REA_ASAR_MAX_HEADER_BYTES` (at most 256 MiB) when set. An oversized header is
|
||||
not parsed; selecting a member path does not bypass admission, and the page
|
||||
stays unauthorized. The header cache separately retains at most that many bytes
|
||||
of already-admitted encoded headers across eight archives. Evicting that cache does not raise admission.
|
||||
@@ -0,0 +1,70 @@
|
||||
# ELF note tables
|
||||
|
||||
`inspect_elf_notes` / `inspect-elf-notes` answers whether one selected local
|
||||
ELF32/ELF64 image declares `PT_NOTE` program headers or `SHT_NOTE` sections,
|
||||
which note owners and types those tables store, and which GNU build-id or
|
||||
ABI-tag fields those notes carry. It reads the file without executing it and
|
||||
does not require a disassembler, debug package, or package catalog.
|
||||
|
||||
```bash
|
||||
rea inspect-elf-notes /absolute/path/to/program --json
|
||||
```
|
||||
|
||||
The CLI resolves relative paths against the caller's working directory. MCP
|
||||
requires an absolute filesystem path and preserves that exact selection:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inspect_elf_notes",
|
||||
"arguments": { "path": "/artifacts/program" }
|
||||
}
|
||||
```
|
||||
|
||||
## Observations
|
||||
|
||||
The inline Evidence result contains the artifact path, SHA-256, and byte length.
|
||||
`tables` lists each declared note program header or section, including the
|
||||
section name when a string table is present. Zlib-compressed section-name
|
||||
tables are decompressed within the selected file-size budget. An unsupported
|
||||
compression type leaves section names unknown and adds a limitation; note bytes
|
||||
remain independently examined. Each `entries[]` item reports owner, type,
|
||||
descriptor SHA-256, and a hex preview for descriptors of 64 bytes or less.
|
||||
|
||||
For GNU notes, `gnu.build_id_hex`, `gnu.abi_tag`, or `gnu.gold_version` are
|
||||
filled when the descriptor matches that type. Other owners keep `gnu` null.
|
||||
|
||||
`PT_NOTE` and `SHT_NOTE` are examined independently. The same file range may
|
||||
appear twice when both tables declare it.
|
||||
|
||||
A missing table list is observed absence of those declarations. It is not proof
|
||||
the image never carried notes in another container or overlay.
|
||||
|
||||
## Limits and failures
|
||||
|
||||
The selected file is limited to 64 MiB by default (512 MiB maximum). At most
|
||||
32 note entries are examined by default across every table. Retained note
|
||||
names, section names, and GNU descriptor text share a scan budget based on
|
||||
the source bytes plus any decoded section-name table, capped at
|
||||
`max_file_bytes`. The raw source and decoded table must also fit together
|
||||
within that ceiling. If admission fails, the error reports the required
|
||||
`max_file_bytes`; raising it can admit the decoded table up to the operation's
|
||||
512 MiB maximum. Once admitted, raising that setting does not increase the
|
||||
scan budget for the same source and decoded names. Repeated table ranges count again. Each descriptor range is hashed once,
|
||||
and each GNU version's trailing NUL run is scanned once; neither walk may
|
||||
exceed that byte ceiling. Malformed ELF headers, truncated header
|
||||
tables, declared note tables that extend past the file, and truncated
|
||||
note entries fail without partial success. ELF extended
|
||||
numbering (`PN_XNUM`, including a section count stored when `e_shnum` is 0) is
|
||||
unsupported and returns an unsupported-target outcome rather than invalid-input
|
||||
recovery.
|
||||
|
||||
`SHF_COMPRESSED` note sections return `unsupported_target` before their payload
|
||||
is interpreted or decompressed. Their compression header is storage metadata,
|
||||
not a note header. The current result requires physical file offsets for each
|
||||
note and descriptor, which decoded compressed notes cannot provide. This refusal
|
||||
does not label compressed note storage as malformed or allocate its declared
|
||||
decoded size. Compressed section-name tables remain supported within the limits
|
||||
above.
|
||||
|
||||
This workflow does not execute the image or verify GNU build-id uniqueness
|
||||
against package catalogs.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Erlang BEAM files
|
||||
|
||||
`inspect_erlang_beam` / `inspect-erlang-beam` answers whether one selected
|
||||
local file is a `FOR1`/`BEAM` IFF container, which chunks that form stores, and
|
||||
which atom, export, import, lambda, and Code-header fields those chunks carry.
|
||||
It reads the file without executing bytecode and does not require an Erlang
|
||||
installation or BEAM emulator.
|
||||
|
||||
```bash
|
||||
rea inspect-erlang-beam /absolute/path/to/app.beam --json
|
||||
```
|
||||
|
||||
The CLI resolves relative paths against the caller's working directory. MCP
|
||||
requires an absolute filesystem path and preserves that exact selection:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inspect_erlang_beam",
|
||||
"arguments": { "path": "/artifacts/app.beam" }
|
||||
}
|
||||
```
|
||||
|
||||
## Observations
|
||||
|
||||
The inline Evidence result contains the artifact path, SHA-256, and byte length.
|
||||
`chunks` lists every IFF chunk name, file range, and payload SHA-256.
|
||||
Repeated names retain separate chunk occurrences. Decoded tables and the Code
|
||||
header use the last occurrence of each name, matching OTP's loader; the chunk
|
||||
inventory still exposes earlier payloads and their source ranges.
|
||||
The BEAM form size bounds the parsed chunks. Bytes after the declared form are
|
||||
ignored by the parser but remain part of the selected artifact's byte length
|
||||
and SHA-256.
|
||||
|
||||
When a selected `AtU8` or `Atom` table is decoded, `atoms` is the 1-based name table and
|
||||
`module` is atom 1. Both the pre-OTP 28 table and the OTP 28+ compact table
|
||||
(negated count, compact-encoded name lengths) are read. `exports`, `imports`, and `lambdas` resolve atom indices to
|
||||
those names when the table is present; unresolved indices keep `function` or
|
||||
`module` null.
|
||||
|
||||
`code` reports the Code chunk instruction-set, opcode maximum, label count,
|
||||
function count, and the instruction stream's file range. Missing optional
|
||||
tables are null, not empty-everywhere.
|
||||
|
||||
A zero-byte `AtU8` falls back to an available legacy `Atom` table, following
|
||||
[OTP 20.3's atom selection](https://github.com/erlang/otp/blob/a113f6117fd696ea6f84ed754055b4ec97a7ccb2/erts/emulator/beam/beam_load.c).
|
||||
A nonempty `AtU8` retains UTF-8 precedence, including an explicit zero atom
|
||||
count; malformed nonempty data fails instead of falling back. An empty atom
|
||||
chunk without an alternate table still fails its required count header.
|
||||
Absent and zero-byte optional `FunT` chunks produce `lambdas: null`, while a
|
||||
four-byte zero row count produces `lambdas: []`. This follows
|
||||
[OTP 29's positive-size lambda parsing rule](https://github.com/erlang/otp/blob/550d7b7898706c7822362c42e7b93120c1d1f29a/erts/emulator/beam/beam_file.c).
|
||||
Empty payloads retain their ranges and SHA-256 in the chunk inventory. These
|
||||
rules apply to the last occurrence of each chunk name; an empty final occurrence
|
||||
does not revive an earlier payload of that name. Nonempty truncated tables remain
|
||||
format failures.
|
||||
|
||||
## Limits and failures
|
||||
|
||||
The selected file is limited to 64 MiB by default (512 MiB maximum). At most
|
||||
64 chunks and 4096 atoms are examined by default, and at most 65536 export,
|
||||
import, and lambda rows together. Malformed `FOR1`/`BEAM` headers, truncated
|
||||
chunks, and `AtU8` names that are not valid UTF-8 fail without partial success.
|
||||
|
||||
This workflow does not execute bytecode, inflate `LitT` literals, or decode
|
||||
`Attr`/`CInf` external-term payloads. Complete coverage describes this static
|
||||
chunk and table report; it does not establish that an Erlang runtime can load
|
||||
or execute the module.
|
||||
@@ -19,8 +19,10 @@ rea inspect-evm-interface ./runtime.bin raw --json
|
||||
|
||||
Initial real verification covers flat legacy bytecode on Linux x64 and unchanged
|
||||
bundled EVMole 0.9.3. EOF-style EF00 containers return `unsupported_target`,
|
||||
with the selected path and format reason. Provider/configuration failures retain
|
||||
their distinct unavailable-provider or capability classification.
|
||||
with the selected path and format reason. Selected-path resolution errors
|
||||
`ENOENT`, `ENOTDIR`, `ELOOP`, and `ENAMETOOLONG` are `invalid_request` path
|
||||
issues. Permission, resource, cancellation, provider, and cleanup failures retain
|
||||
their distinct classifications.
|
||||
The host must already provide util-linux `prlimit`, normally `/usr/bin/prlimit`;
|
||||
`REA_EVM_PRLIMIT_COMMAND` can select another absolute executable. REA installs
|
||||
no system tools and changes no user configuration. [Upstream provenance and
|
||||
@@ -43,7 +45,8 @@ license](https://github.com/morluto/rea/blob/main/third_party/evmole/README.md)
|
||||
map from the selected bytes. Integers use decimal strings; byte strings use hex,
|
||||
and scalar keys retain their types. The recorded offset/length addresses the
|
||||
original bytecode, so summary delivery does not copy an opaque CBOR payload.
|
||||
Nested containers have partial scalar coverage; unsupported or malformed
|
||||
Nested containers have partial scalar coverage; map keys are still checked for
|
||||
duplicates throughout nested maps and arrays. Unsupported or malformed
|
||||
candidates report `not-decoded` with a diagnostic. Decoding is bounded to 64
|
||||
container levels and the terminal payload's encoded size.
|
||||
- An unavailable trailer does not prove metadata absence or Solidity origin.
|
||||
@@ -110,7 +113,9 @@ address-space limit and 30 CPU seconds. The worker command deadline is
|
||||
`timeout_ms` (default 30000 ms, integer 1 through 2147483647) on the next call,
|
||||
or `--timeout-ms` on `rea inspect-evm-interface`. Omission keeps 30000 ms.
|
||||
Those byte, address-space, and CPU ceilings have no runtime override, and
|
||||
`timeout_ms` does not raise them. Virtual
|
||||
`timeout_ms` does not raise them. An oversized selected carrier returns a
|
||||
non-retryable `resource_constraint` with resource `file-size` and its fixed
|
||||
input allowance in `reported_limits.maximum_input_bytes`. Virtual
|
||||
address space differs from resident memory. The worker retains inherited tighter
|
||||
soft/hard limits, reports its configured soft limits inline and leaves hard limits
|
||||
unchanged. WASM trap reservations are disabled
|
||||
|
||||
@@ -50,6 +50,27 @@ git submodule update --init third_party/binwalk third_party/unblob
|
||||
Normal REA builds and npm packages do not include or build these sources or
|
||||
engine binaries. See [upstream provenance](https://github.com/morluto/rea/blob/main/third_party/README.md).
|
||||
|
||||
### Windows submodule checkout
|
||||
|
||||
On Windows, the Unblob checkout stops with `error: invalid path`. Several
|
||||
upstream test fixture names under `tests/integration/` contain characters,
|
||||
trailing dots, or trailing spaces that NTFS does not allow; REA does not use
|
||||
those fixtures. Keep the clone, exclude that directory, and retry from the
|
||||
repository root in PowerShell:
|
||||
|
||||
```powershell
|
||||
git -C third_party/unblob config core.protectNTFS false
|
||||
git -C third_party/unblob sparse-checkout set --no-cone '/*' '!/tests/integration/'
|
||||
git submodule update third_party/unblob
|
||||
```
|
||||
|
||||
Both settings are required. While `core.protectNTFS` is enabled, Git for
|
||||
Windows also rejects index paths that the sparse pattern excludes; the pattern
|
||||
keeps the invalid names out of the worktree. The setting applies only to the
|
||||
Unblob submodule. In Git Bash, prefix the `sparse-checkout` command with
|
||||
`MSYS_NO_PATHCONV=1`; otherwise `!/tests/integration/` is rewritten as a
|
||||
Windows path.
|
||||
|
||||
## CLI and MCP
|
||||
|
||||
```sh
|
||||
|
||||
@@ -108,7 +108,12 @@ server; older servers keep the complete request after schema discovery.
|
||||
`build_id_candidates` preserves distinct IDs. `build_id` is populated only
|
||||
when all declared note ranges were examined and one ID was found;
|
||||
conflicting IDs or malformed/bounded note metadata make coverage partial.
|
||||
Nonempty GNU build-ID descriptors up to 64 bytes are retained as lowercase
|
||||
hexadecimal, including IDs shorter than four bytes.
|
||||
Matching bytes outside declared note ranges cannot supply a build ID.
|
||||
Compressed `SHT_NOTE` sections are skipped with an unsupported-compression
|
||||
limitation and partial coverage; IDs from other note ranges remain candidates.
|
||||
Encoded note storage is never interpreted as note headers or inflated.
|
||||
- Labeled strings must fit their complete grammar. `dart_version_capped`
|
||||
and `toolchain_capped` independently report labels omitted by grammar or
|
||||
projection bounds; either makes identification coverage partial. Values
|
||||
@@ -152,9 +157,16 @@ server; older servers keep the complete request after schema discovery.
|
||||
- **Selected ABI.** AOT inspection applies the library budget to the selected
|
||||
ABI after selection; an oversized unselected library does not block it.
|
||||
Undefined dynamic-symbol imports are not treated as snapshot exports.
|
||||
A retained section directory without `SHT_DYNSYM` uses the same bounded
|
||||
`PT_DYNAMIC` symbol description as a section-stripped image. Malformed
|
||||
present symbol-table sections remain failures.
|
||||
Section-stripped images require a bounded symbol count from `DT_HASH` or
|
||||
`DT_GNU_HASH`; layouts without either are refused. Symbol names and their
|
||||
terminators must fit their linked string table.
|
||||
terminators must fit their linked string table. Only dynamic entries used for
|
||||
symbol discovery are interpreted as numeric bounds. ABI-ignored payloads,
|
||||
including [`DT_BIND_NOW`](https://gabi.xinuos.com/elf/08-dynamic.html#dynamic-section),
|
||||
do not change discovery; their stored bytes still contribute to the selected
|
||||
artifact's digest.
|
||||
- REA performs **no hash-to-SDK lookup**: mapping the snapshot hash to a
|
||||
Dart SDK release requires an external dataset and is deliberately out of
|
||||
scope for this family.
|
||||
|
||||
@@ -6,6 +6,8 @@ For remote devices, pass a host with an optional port (`host[:port]`; bracket IP
|
||||
|
||||
MCP exposes `list_frida_devices`, `list_frida_processes`, `start_frida_session`, `load_frida_script`, `resume_frida_session`, `unload_frida_script`, `frida_session_status`, and `close_frida_session`. A spawned process starts paused so scripts can load first. Closing unloads session scripts and detaches. If a spawn remains paused, REA resumes it only after script cleanup or session detach confirms the instrumentation is released; if both cleanup paths fail, the target stays paused and the cleanup error is retained. REA never kills the target. MCP sessions end with the server process. The one-shot CLI command `instrument-with-frida` accepts one inline script or script file, observes messages for a bounded duration, and returns Evidence with the source hash and captured messages.
|
||||
|
||||
`instrument-with-frida --json` returns the Evidence record directly, matching MCP. Consumers of the earlier `{evidence, cleanup_error}` CLI wrapper should read the record at the JSON root and the session cleanup observation at `normalized_result.cleanup_error`. If final provider cleanup fails or cancellation arrives during it, the typed error retains completed Evidence in `details.partial_observation`. Discovery commands retain their device or process report in the same field.
|
||||
|
||||
For state and capture-coverage checks, pass `{"session_id":"SESSION_ID","detail":"summary"}` to `frida_session_status`. Each call reads the observed session state and retains the complete observation. The reply is an `inspect_analysis_view` Evidence summary with the session identity, state, scripts, `messages_retained`, and `messages_truncated`; message payloads remain in its `parent_evidence_id`. The count covers retained queued messages, not every target event. Omitted `detail` or `detail=complete` preserves the existing complete reply.
|
||||
|
||||
A summary's selected fields look like this (excerpt):
|
||||
|
||||
+12
-6
@@ -23,13 +23,19 @@ not name its entry function `entry`. MCP uses `open_binary`, `list_procedures`,
|
||||
`procedure_info`, `read_function_instructions`, and `analyze_function` with the
|
||||
same admitted target and provider semantics.
|
||||
|
||||
The classifier validates MZ page counts, initialized module length, header and
|
||||
The DOS MZ parser validates page counts, initialized module length, header and
|
||||
relocation-table bounds, relocation destinations, and the initialized entry
|
||||
point. It distinguishes DOS load-module and relocation bytes from the Windows
|
||||
new-header field. PE remains PE; NE, LE, and LX declarations are explicitly
|
||||
unsupported. A damaged declared Windows header does not silently become DOS.
|
||||
Inventory classification returns `unknown` when its bounded prefix cannot
|
||||
establish the format; this is distinct from the complete target admission check.
|
||||
point using the available structural bytes and actual file length. It reports
|
||||
those DOS facts separately from Windows-header evidence. A recognized PE
|
||||
signature remains PE; recognized NE, LE, and LX headers are explicitly
|
||||
unsupported. A nonzero Windows-header pointer without a recognized signature
|
||||
remains an unresolved candidate, even when the DOS structure validates:
|
||||
automatic target selection fails closed and reports both observations.
|
||||
REA does not infer DOS intent from padding or infer a damaged Windows header
|
||||
from the pointer alone. Inventory classification is a bounded-prefix format
|
||||
hint; it returns `unknown` for that candidate or when its prefix cannot
|
||||
establish the format. That result is distinct from complete DOS validation and
|
||||
does not decide target admission.
|
||||
|
||||
Ghidra imports a private target snapshot with `MzLoader`, language
|
||||
`x86:LE:16:Real Mode`, and compiler specification `default`. These settings,
|
||||
|
||||
+30
-11
@@ -61,7 +61,7 @@ rea inspect-go-binary ./application --detail summary --evidence_output ./go-evid
|
||||
`--evidence_output` is required for CLI summary delivery and never overwrites an
|
||||
existing file. The default CLI/MCP reply remains complete.
|
||||
|
||||
[Measured workflows](../experiments/analysis-efficiency/go-build-views.md) include
|
||||
[Measured workflows](https://github.com/morluto/rea/blob/42e1a17d6e6c0487f17be0bae248553c4caba7f7/experiments/analysis-efficiency/go-build-views.md) include
|
||||
catalog repetition and extra calls. Identity/count questions benefit from a
|
||||
single summary. In the tested Codex full-catalog configuration, a compound
|
||||
question about identity and one dependency uses fewer tokens in captured request JSON with
|
||||
@@ -109,17 +109,34 @@ module record and no dependency records has an observed empty dependency list.
|
||||
|
||||
## Supported boundary
|
||||
|
||||
The built-in TypeScript reader supports ELF, PE and thin Mach-O images with Go's
|
||||
inline or historical pointer build-info encoding. Source ranges refer to the
|
||||
original stable file snapshot, including pointer-backed strings. It does not
|
||||
scan arbitrary byte strings as compiler metadata or interpret a fat Mach-O
|
||||
container as one selected architecture.
|
||||
The built-in TypeScript reader supports ELF, PE and thin Mach-O images, and one
|
||||
selected slice of a universal Mach-O, with Go's inline or historical pointer
|
||||
build-info encoding. Source ranges refer to the original stable file snapshot,
|
||||
including pointer-backed strings. Legacy pointer-backed fields are decoded at
|
||||
the width declared by Go's build-info record, independently of the image's ELF
|
||||
class. It does not scan arbitrary byte strings as compiler metadata.
|
||||
|
||||
A universal (FAT) Mach-O needs `architecture` (`x86`, `x86_64`, `arm`
|
||||
or `arm64`; CLI `--architecture`). REA reads its own FAT table, without `lipo`,
|
||||
and validates the selected slice's range, alignment and Mach-O header CPU
|
||||
against the table. The result keeps the universal file as `artifact` (its
|
||||
SHA-256 and size), adds `selected_slice` with the slice offset, length, raw CPU
|
||||
type/subtype and the FAT table digest, and reports every source range as a
|
||||
file offset inside that slice. Without `architecture`, or when the file has no
|
||||
such slice or several, the request fails on `architecture` and lists the slices
|
||||
present. `architecture` on any other image is rejected rather than ignored.
|
||||
|
||||
For ELF images without a named build-info section, discovery checks each
|
||||
nonempty writable, non-executable load segment in program-header order. This
|
||||
includes sectionless PIE images with metadata in a later data segment. Named
|
||||
sections retain priority, and alignment, file mapping and record validation
|
||||
remain required.
|
||||
remain required. When ELF section names are unreadable, limitations report that
|
||||
coverage gap; the fallback search policy is unchanged.
|
||||
|
||||
A named ELF or Mach-O build-info section selects the record's discovery range.
|
||||
For inline encoding, the following version and module strings may continue past
|
||||
that section into its file-backed load mapping; their bytes are still checked
|
||||
against the mapping and the existing aggregate string limit.
|
||||
|
||||
Historical moduleless Go binaries can store their empty module-string header in
|
||||
declared zero-initialized virtual memory rather than file-backed bytes. The reader
|
||||
@@ -146,10 +163,12 @@ and `reported_limits.maximum_input_bytes`. Select a suitable input within that
|
||||
fixed allowance; changing an output-write or transport budget does not admit it.
|
||||
|
||||
Resource guards bound the selected file and cumulative header searches to 256 MiB
|
||||
each, aggregate embedded strings
|
||||
to 1 MiB, structural table decoding to 16 MiB and the complete normalized metadata
|
||||
report to 8 MiB. Identical search spans with the same virtual alignment are
|
||||
searched once; partially overlapping spans consume the cumulative search budget
|
||||
each, aggregate embedded string contents to 1 MiB (varint length prefixes are
|
||||
framing and do not count toward this allowance), structural table decoding to
|
||||
16 MiB and the complete normalized metadata report to 8 MiB. Inline strings must
|
||||
also fit within their actual mapped source range. Identical search spans with
|
||||
the same virtual alignment are searched once; partially overlapping spans
|
||||
consume the cumulative search budget
|
||||
and fail with a CPU resource constraint when it is exhausted. Oversized results
|
||||
fail without partial success. MCP also applies
|
||||
its [response transport budget](mcp-contracts.md), which counts both text and
|
||||
|
||||
@@ -34,6 +34,11 @@ The same CLI commands locate a PCK at the beginning of a file or through its
|
||||
payloads or discover packs behind additional trailing signatures. The root
|
||||
content SHA-256 covers the whole carrier; its content classification remains
|
||||
native, while the inventory records the PCK role and exact pack bounds.
|
||||
An EOF marker is only a candidate: an invalid size or a pointed-to location
|
||||
without a `GDPC` header leaves native classification in place. Once the
|
||||
trailer points to a pack header, malformed or unsupported PCK content remains
|
||||
an error. This recognition boundary follows the Godot loader at pinned source
|
||||
revision [06d1e7a](https://github.com/godotengine/godot/blob/06d1e7a34ccde4029eed53d018cfde77dfe771d5/core/io/file_access_pack.cpp#L2099-L2146).
|
||||
Ordinary native `open_binary` detection remains unchanged.
|
||||
|
||||
## MCP and selected facts
|
||||
|
||||
@@ -27,11 +27,38 @@ selected fields.
|
||||
Conflicting base architectures retain both values, mark object/report/target
|
||||
coverage partial and annotate the affected kernels. CUBIN flags establish a base
|
||||
architecture: `base-only` explicitly leaves feature-profile agreement unknown,
|
||||
including `a` variants. A standalone declaration is `single-source`, and
|
||||
including `a` and `f` variants. A standalone declaration is `single-source`, and
|
||||
unexamined payloads remain `unexamined`. An exact AMDGPU target is normalized at
|
||||
its note owner for comparison with a Clang bundle declaration; raw values remain
|
||||
intact. Unresolved feature comparisons stay `unknown`.
|
||||
|
||||
A HIP target ID identifies a toolchain target, not its payload representation.
|
||||
Recognized raw or wrapped LLVM bitcode stays `unsupported` for kernel metadata
|
||||
inspection, with the bundle ID, range and selected payload digest retained.
|
||||
Bitcode validity and inner targets remain unexamined; malformed recognized ELF
|
||||
still reports `malformed`. Standalone bitcode is outside GPU container coverage.
|
||||
|
||||
HIP bundle and metadata note recognition accept both the legacy `amdgcn` triple
|
||||
and LLVM's `amdgpu` subarchitecture triples, including declared generic processors
|
||||
such as `gfx11-generic` and `gfx9-4-generic`. Notes with the empty or explicit
|
||||
`unknown` environment use the same processor and feature comparison while
|
||||
retaining their raw triple spelling. CUDA's legacy fatbinary compression flag is
|
||||
retained as an unsupported codec with its encoded and decoded extents;
|
||||
compressed bytes are not treated as PTX text. CCOB is recognized by the exact
|
||||
four signature bytes `CCOB`; high-bit-corrupted bytes are not decoded as ASCII
|
||||
and accepted as a bundle. CCOB v1 has no stored total size: the completed zlib
|
||||
or Zstd stream determines its encoded extent. Embedded `CCOB` text is ordinary
|
||||
compressed data; zero-byte alignment after the stream belongs to neither
|
||||
payload. If decoding fails or its codec is unsupported, a later `CCOB` marker
|
||||
is only an uncertain recovery candidate. The affected row retains that
|
||||
limitation and discovery remains partial.
|
||||
|
||||
The declared decoded length bounds decompression. An understated length can
|
||||
stop decoding before codec completion, so any subsequent recovery extent stays
|
||||
unknown; the decoder does not expand its allowance to prove the bad declaration.
|
||||
Interrupted observations omit unfinished v1 rows. A terminal capacity row
|
||||
qualifies its retained range as the containing tail and does not infer siblings.
|
||||
|
||||
`cuda_target_header` retains the OS ABI, normalized raw `e_flags` and exact
|
||||
header location. CUDA OS ABI `0x33` and the observed `0x41` flags layout use
|
||||
different architecture fields; they are decoded at one ABI-aware owner.
|
||||
@@ -43,8 +70,8 @@ target remains unexamined; an empty filtered result does not establish that
|
||||
no enclosed code declares that target. Discovering every inner declaration
|
||||
requires decoding those payloads.
|
||||
|
||||
HIP IDs with one or two separators before the architecture retain the declared
|
||||
target. If a recognized AMDGPU bundle ID does not expose a target, the same
|
||||
HIP bundle IDs retain the declared processor and v2-v3 `+feature` suffixes for
|
||||
exact selection. If a recognized AMDGPU bundle ID does not expose a target, the same
|
||||
bounded note-discovery owner used for standalone AMDGPU files establishes it
|
||||
before filtering. Those directory/note reads share the inspection work budget;
|
||||
successive queries can select the target returned by inventory.
|
||||
@@ -81,15 +108,42 @@ Kernel representations have different meanings:
|
||||
- PTX reports parameter declarations and virtual registers. Shared bytes cover
|
||||
supported static declarations inside that entry; they do not establish module
|
||||
shared memory, dynamic allocation or physical device resources.
|
||||
PTX 1.0–1.3 declares entry parameters in the body; PTX 1.4 and later uses the
|
||||
entry parameter list. Entry-scoped `.pragma` statements before the body do
|
||||
not end the declaration or suppress its body resources. A `.target
|
||||
compute_xx` spelling is retained as written;
|
||||
NVIDIA PTX defines it as a synonym for `.target sm_xx` when comparing its
|
||||
target identity with the fatbin declaration. `.callprototype` formal
|
||||
parameters are excluded from entry virtual-register counts. Parameter names
|
||||
remain available when pointer qualifiers are understood or an unsupported
|
||||
qualifier prevents layout decoding. A pointer's `.align` describes the
|
||||
pointed-to memory and does not change parameter layout alignment. Spaced,
|
||||
joined and partly joined pointer qualifiers have the same meaning. Parameter
|
||||
alignment before or after the scalar type retains its layout and name.
|
||||
Parameter names and following declarations are retained when an array
|
||||
extent uses a parenthesized expression or when dimensions are
|
||||
multidimensional, even though those forms do not currently yield a layout.
|
||||
PTX target selection uses the highest-numbered module-scope `.target`
|
||||
directive, including directives after entry declarations; unsupported or
|
||||
conflicting target profiles leave the effective target unknown.
|
||||
Scalar register declarations count each bare or percent-prefixed name and
|
||||
each parameterized range. Unsupported declaration forms or overflowing totals
|
||||
each parameterized range, including compact keywords such as `.reg.b32`.
|
||||
Unsupported declaration forms or overflowing totals
|
||||
retain an unknown count and partial decoding coverage. Unsupported parameter
|
||||
layouts and unknown shared-memory declarations likewise retain their known
|
||||
facts, explicit limitations and partial coverage through retained pages.
|
||||
- CUBIN identifies CUDA entry symbols and reads numeric `nv.info` records and
|
||||
native section declarations. Global register declarations also cover compiler
|
||||
- CUBIN identifies CUDA entry symbols and reads numeric `nv.info` records,
|
||||
including V2 kernel-parameter sizes, and native section declarations. Global
|
||||
register declarations also cover compiler
|
||||
versions that leave the older text-section register field empty.
|
||||
- AMDGPU reads v3+ MessagePack notes. Argument counts include hidden ABI arguments
|
||||
Conflicting register declarations keep the physical count unknown, preserve the
|
||||
kernel's other facts, and mark object/report/target decoding coverage partial.
|
||||
- AMDGPU reads v3+ MessagePack notes. V3 processor identity comes from the
|
||||
`EF_AMDGPU_MACH` field in ELF `e_flags`; known processor values are selectable
|
||||
even when the note omits `amdhsa.target`. This inventory reports the processor
|
||||
only; it does not interpret version-specific feature flags. Unknown processor values remain unknown. A known
|
||||
processor conflict between ELF flags and note metadata leaves the processor
|
||||
unresolved. Argument counts include hidden ABI arguments
|
||||
when present; SGPR/VGPR counts and fixed group/private segment sizes retain
|
||||
their declared meanings. Legacy YAML metadata remains unsupported.
|
||||
|
||||
@@ -119,7 +173,9 @@ A location with `container_id: null` uses original file offsets. Other locations
|
||||
use that inventoried object's decoded byte coordinates. Follow its parent,
|
||||
encoded location and digest to trace decompressed metadata back to a native
|
||||
section and the original file. Decoded offsets are never presented as physical
|
||||
file offsets.
|
||||
file offsets. Reads from an ELF or PE GPU section stay within that declared
|
||||
section extent, so neighboring native section bytes cannot complete a
|
||||
truncated embedded bundle header.
|
||||
|
||||
The CLI uses the same service and contracts:
|
||||
|
||||
@@ -164,3 +220,5 @@ failures preserve earlier successfully parsed declarations and the original
|
||||
failure reason. Standalone PTX recognition tries a small header first, then
|
||||
continues within the existing 16 MiB text budget when leading comments or
|
||||
whitespace obscure its directives; admitted full-file probe bytes are reused.
|
||||
After those comments and whitespace, `.version` must be the first PTX module
|
||||
token; later PTX-looking text does not identify an arbitrary binary as PTX.
|
||||
@@ -36,8 +36,9 @@ The MCP tool `project_harmony_application_graph` takes the same
|
||||
|
||||
- exact component paths, artifact IDs, and hashes (manifests, Ark bytecode,
|
||||
resources, native libraries, JavaScript, signing)
|
||||
- a packaging-model hint: Stage is claimed only from a `module.json` entry,
|
||||
FA only from `config.json`, otherwise `unknown`
|
||||
- a packaging-model hint: Stage is claimed only from a `module.json` entry
|
||||
outside a classified resource path, FA only from `config.json` outside a
|
||||
classified resource path, otherwise `unknown`
|
||||
- FA resources under `assets/<module>/resources/` as well as Stage `resources/`
|
||||
- unavailable component paths with unknown IDs and hashes, including encrypted entries; these make projection coverage partial
|
||||
- App Pack child package paths without recursive inventory
|
||||
|
||||
+39
-26
@@ -206,7 +206,16 @@ image, the single record whose name pointer reaches that image's name string and
|
||||
whose count equals the image's method count. It then requires exactly one
|
||||
`codeGenModulesCount`/`codeGenModules` pair that lists exactly those records. No
|
||||
symbols are needed, so stripped builds work. A method's token row id selects its
|
||||
slot in the module's method pointer array.
|
||||
slot in the module's method pointer array. Within one image, each method must
|
||||
claim a distinct MethodDef token row; duplicate rows are refused before any
|
||||
linked method table or seed output is published. Row ids may repeat across
|
||||
different images, and distinct rows may still resolve to the same address when
|
||||
the binary uses identical-code folding.
|
||||
|
||||
For ELF, a repeated load mapping that resolves a complete module record to the
|
||||
same virtual address and file bytes contributes one record. Distinct virtual
|
||||
record addresses remain distinct candidates, and conflicting file mappings
|
||||
remain malformed.
|
||||
|
||||
Module records establish names through their declared NUL-terminated string pointers. NUL/0xFF padding, spaces, Unicode and suffix-shared storage are supported. A pointer to a longer string does not match just its suffix; a pointer directly into a shared suffix may name it. Exact reversed UTF-8 matching avoids rescanning the file for every name and retains duplicate-name owners until module records resolve them. A contributor investigated a Linux
|
||||
`GameAssembly.so` from Unity 2023.2.13f1 whose static registration was not located. When no static pair is resolved on x86-64, the reader searches executable ranges for bytes consistent with RIP-relative LEA/MOV references to module-array candidates. Exactly one referenced array candidate must remain. `code_gen_modules_field` is then `null`, and Evidence is **inferred**: instruction boundaries, the absence of a static registration elsewhere, and runtime use were not verified. The module records and slots themselves remain file observations. Static-table associations are **derived**. Otherwise the result is `code-registration-not-found`.
|
||||
@@ -239,7 +248,9 @@ The result adds:
|
||||
`rva` (address minus `image_base`), both hexadecimal strings. `state` is
|
||||
`code` when the module slot holds an unambiguously mapped executable address, `no-body` when an observed slot is zero,
|
||||
as for abstract, extern and most generic methods, and `unknown` when no type
|
||||
range in any image holds the method or a symbol relocation leaves its slot unresolved.
|
||||
range in any image holds the method, a symbol relocation leaves its slot
|
||||
unresolved, or dyld will bind a Mach-O slot. The raw word in a dyld-bound
|
||||
slot is not treated as the resolved address.
|
||||
`address` and `rva` are `null` unless `state` is `code`. The summary counts
|
||||
each state in `counts.method_address_states`. Ghidra seeds are written only
|
||||
for `code` rows.
|
||||
@@ -248,10 +259,13 @@ The result adds:
|
||||
field and parameter index with `type`, the index into the binary's
|
||||
`Il2CppType` table, and `name`, rendered from that table: C# keywords for
|
||||
primitives (`int`, `string`, `object`), `Namespace.Outer+Inner` for type
|
||||
definitions, `T[]`, `T[,]` and `T*`, generic instances as
|
||||
definitions, `T[]` for vectors, `T[*]` for rank-one multidimensional arrays,
|
||||
`T[,]` for rank-two arrays and `T*`, generic instances as
|
||||
`System.Collections.Generic.List<string>` and generic parameters by their
|
||||
metadata name (`TKey`). A trailing `&` marks a by-reference type. `name` is
|
||||
`null` only for type index `-1`.
|
||||
metadata name (`TKey`). Nested generic arguments stay with the component
|
||||
that declares them, for example `Game.Outer<int>+Inner<string>` or
|
||||
`Game.Outer<int>+Leaf` when the nested type adds no parameters. A trailing
|
||||
`&` marks a by-reference type. `name` is `null` only for type index `-1`.
|
||||
|
||||
`binary` also records `types_field` and `types_count`: the address of
|
||||
`Il2CppMetadataRegistration.typesCount` and its value. That record is found as
|
||||
@@ -268,27 +282,27 @@ Il2CppType byref flag in different bits, so a rendered name could gain or lose
|
||||
|
||||
The builds checked are listed after the module search rules above.
|
||||
|
||||
| Reason | Category | Meaning |
|
||||
| --------------------------------- | ----------- | ------------------------------------------------------------------------------------------------- |
|
||||
| `unsupported-container` | unsupported | Not a 64-bit little-endian Mach-O, PE or ELF image (ELF: AArch64 or x86-64 with dynamic section). |
|
||||
| `slice-selection-required` | unsupported | A universal Mach-O was given without `binary_architecture`. |
|
||||
| `slice-not-found` | unsupported | The requested slice is absent, or a thin binary was given an architecture. |
|
||||
| `unsupported-pointer-encoding` | unsupported | Mach-O chained fixups or Android packed (APS2) ELF relocations; pointers not decoded. |
|
||||
| `malformed-container` | input error | The container headers are damaged. |
|
||||
| `code-gen-modules-not-found` | input error | An image has no module record; often a binary from a different build. |
|
||||
| `ambiguous-code-gen-module` | input error | More than one module record matches an image. |
|
||||
| `code-registration-not-found` | input error | No unique module table or executable-byte array candidate was resolved. |
|
||||
| `invalid-method-token` | input error | A method token is not a method row inside its module's pointer count. |
|
||||
| `invalid-method-pointer` | input error | A slot is unavailable or its nonzero address lacks unambiguous executable file coverage. |
|
||||
| `metadata-registration-not-found` | input error | No single MetadataRegistration matches the type-definition count. |
|
||||
| `invalid-type` | input error | A type index or `Il2CppType` record is out of range, unmapped or malformed. |
|
||||
| `unsupported-type-kind` | unsupported | A valid type kind has no implemented rendering. |
|
||||
| Reason | Category | Meaning |
|
||||
| --------------------------------- | ----------- | --------------------------------------------------------------------------------------------------- |
|
||||
| `unsupported-container` | unsupported | Not a 64-bit little-endian Mach-O, PE or ELF image (ELF: AArch64 or x86-64 with dynamic section). |
|
||||
| `slice-selection-required` | unsupported | A universal Mach-O was given without `binary_architecture`. |
|
||||
| `slice-not-found` | unsupported | The requested slice is absent, or a thin binary was given an architecture. |
|
||||
| `unsupported-pointer-encoding` | unsupported | Mach-O chained fixups or Android packed (APS2) ELF relocations; pointers not decoded. |
|
||||
| `malformed-container` | input error | The container headers are damaged. |
|
||||
| `code-gen-modules-not-found` | input error | An image has no module record; often a binary from a different build. |
|
||||
| `ambiguous-code-gen-module` | input error | More than one module record matches an image. |
|
||||
| `code-registration-not-found` | input error | No unique module table or executable-byte array candidate was resolved. |
|
||||
| `invalid-method-token` | input error | A token is outside its module's method-pointer rows, or a MethodDef row is reused within one image. |
|
||||
| `invalid-method-pointer` | input error | A slot is unavailable or its nonzero address lacks unambiguous executable file coverage. |
|
||||
| `metadata-registration-not-found` | input error | No single MetadataRegistration matches the type-definition count. |
|
||||
| `invalid-type` | input error | A type index or `Il2CppType` record is out of range, unmapped or malformed. |
|
||||
| `unsupported-type-kind` | unsupported | A valid type kind has no implemented rendering. |
|
||||
|
||||
Format and selection failures name `binary_path`; capacity refusals remain typed resource errors. Failed linking preserves the metadata source identity, validated counts, selected binary path/architecture and its SHA-256 when observed, plus prior producer observations. It never publishes an incomplete native table as complete. The binary input is bounded to1GiB.
|
||||
|
||||
Scans yield cooperatively in bounded batches. Name-address retention and reverse-trie construction are each limited to65,536 entries/nodes and fallback module-array candidates to64 (`native-index-capacity`); exceeding capacity does not prove absence. Rendered type text has a64MiB UTF-8 cache-workspace guard, separate from the64MiB encoded-report admission, and64 nested rendering frames (`native-type-text-capacity` / `type-nesting-capacity`). Genuine cycles are malformed; unsupported type kinds are explicit coverage failures. Native row/text admission runs before allocation or retention. Unused generic parameter names are read on demand from the same stable metadata snapshot. There is no cross-inspection file cache; validated immutable Evidence is reused for session views.
|
||||
|
||||
ELF RELATIVE writes into zero-fill are kept as a private virtual-pointer overlay. Unresolved supported-width symbol relocations, including RELA PLT entries, remain unknown; stored zeros never establish no-body. COPY, TLS descriptor, REL, packed APS2 and other unsupported relocation encodings fail closed. Input bytes are unchanged.
|
||||
ELF RELATIVE writes into zero-fill are kept as a private virtual-pointer overlay. Unresolved supported-width symbol relocations, including RELA PLT entries, remain unknown only for the bytes their ELF ABI relocation type covers; an adjacent 32-bit relocation does not make a separate 64-bit method slot unknown. Stored zeros never establish no-body. COPY, TLS descriptor, REL, packed APS2 and other unsupported relocation encodings fail closed. Input bytes are unchanged.
|
||||
|
||||
Native address queries batch exact64-bit hexadecimal `addresses` and `states` (`code`, `no-body`, `unknown`), intersecting indices and pagination. Numerically equal address spellings match; original row indices and every shared-body alternative survive:
|
||||
|
||||
@@ -354,16 +368,15 @@ message names one reason:
|
||||
| `nested-type-conflict` | A type is listed as nested in two types, in itself, or in a cycle of declaring types. |
|
||||
| `declaring-type-mismatch` | A method inside a type's method range names a different type, or a method lies outside its type's range. |
|
||||
| `image-range-overlap` | Two images claim the same type definitions. |
|
||||
| `invalid-string` | A name index does not start a string, or the name is unterminated or not valid UTF-8. |
|
||||
| `invalid-string` | A name index is outside the strings section, its string is unterminated, or it is not valid UTF-8. |
|
||||
|
||||
A version field that disagrees with the file's layout, for example a version
|
||||
39 file relabeled as 29, usually surfaces as `unexpected-header-size` or
|
||||
`record-size-mismatch`.
|
||||
|
||||
Two checks are stricter than the IL2CPP runtime: a name index must start a
|
||||
string, and an empty range's start must lie between -1 and the collection size.
|
||||
Every Unity-written file checked so far satisfies both; metadata rewritten by
|
||||
other tools may be rejected.
|
||||
An empty range's start must lie between -1 and the collection size, which is
|
||||
stricter than some runtime paths. String indices are byte offsets; a valid
|
||||
offset may select a suffix of another NUL-terminated name.
|
||||
|
||||
An incomplete inventory is never reported as complete. Failures after a verified
|
||||
snapshot retain partial source Evidence with its SHA-256, byte length and any
|
||||
|
||||
+15
-14
@@ -47,22 +47,23 @@ For runtime instrumentation, see the [Frida guide](./frida-instrumentation.md).
|
||||
|
||||
## Choose a guide
|
||||
|
||||
| Task | Guides |
|
||||
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Identify a desktop installation | [Runtime candidates, evidence and follow-up files](desktop-applications.md) |
|
||||
| Inspect native functions, references, or types | [Native binaries](native-investigation.md), [Go metadata](go-binaries.md), [Rust dependencies](rust-binaries.md), [offline ELF layout](binary-diagnostics.md), [recorded crashes](recorded-crashes.md) |
|
||||
| Select a native provider or import format | [Ghidra semantics](ghidra-provider.md), [Windows](windows-ghidra-p0.md), [DOS](ghidra-dos.md), [raw bytes](raw-binary.md), [MIPS](ghidra-mips.md), [PSP](ghidra-psp.md), [NativeAOT](ghidra-nativeaot.md), [IDA](ida-provider.md), [Kuna](kuna-provider.md), [JEB](jeb-analysis.md) |
|
||||
| Analyze JavaScript or Electron artifacts | [Static analysis](javascript-artifact-reconstruction.md), [tracing and comparisons](javascript-application-workflows.md), [application graph](javascript-application-graph.md), [source recovery](javascript-recovery.md) |
|
||||
| Compare static JavaScript with runtime observations | [Runtime attribution](javascript-runtime-observation.md), [reconciliation](javascript-runtime-reconciliation.md), [Electron observation](electron-observation.md), [Electron fuses](electron-fuses.md) |
|
||||
| Inspect assemblies, packages, or firmware | [Godot PCK](godot-pck.md), [.NET](managed-code-analysis.md), [Python packages](python-packaged-applications.md), [Android](android-analysis.md), [Apktool resources](apktool-resource-analysis.md), [ADB acquisition](adb-device-analysis.md), [Apple](apple-application-analysis.md), [Harmony](harmony-analysis.md), [firmware](firmware-analysis.md), [WASM](wasm-artifacts.md), [EVM](evm-bytecode.md) |
|
||||
| Observe or compare a browser scenario | [CDP observation](browser-observation.md), [scenarios](browser-scenario-contract.md), [runtime evidence](web-runtime.md), [historical captures](web-network-captures.md) |
|
||||
| Serve recorded behavior as an agent environment | [Agent environments](agent-environments.md) |
|
||||
| Trace captured website source | [Source locations](web-source-location.md), [module traces](website-module-trace.md), [script export](website-script-export.md) |
|
||||
| Capture and compare a command | [Process capture](process-capture.md) |
|
||||
| Use CLI/MCP and retain evidence | [CLI](cli.md), [MCP contracts](mcp-contracts.md), [agent prompts](mcp-prompts.md), [obligation ledgers](reconstruction-obligation-ledgers.md) |
|
||||
| Task | Guides |
|
||||
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Identify a desktop installation | [Runtime candidates, evidence and follow-up files](desktop-applications.md) |
|
||||
| Inspect native functions, references, or types | [Native binaries](native-investigation.md), [Go metadata](go-binaries.md), [Rust dependencies](rust-binaries.md), [CPython pyc files](python-pyc.md), [PE certificates](pe-certificates.md), [ELF notes](elf-notes.md), [Erlang BEAM](erlang-beam.md), [offline ELF layout](binary-diagnostics.md), [recorded crashes](recorded-crashes.md) |
|
||||
| Select a native provider or import format | [Ghidra semantics](ghidra-provider.md), [Windows](windows-ghidra-p0.md), [DOS](ghidra-dos.md), [raw bytes](raw-binary.md), [MIPS](ghidra-mips.md), [PSP](ghidra-psp.md), [NativeAOT](ghidra-nativeaot.md), [IDA](ida-provider.md), [Kuna](kuna-provider.md), [JEB](jeb-analysis.md) |
|
||||
| Analyze JavaScript or Electron artifacts | [Static analysis](javascript-artifact-reconstruction.md), [tracing and comparisons](javascript-application-workflows.md), [application graph](javascript-application-graph.md), [source recovery](javascript-recovery.md) |
|
||||
| Compare static JavaScript with runtime observations | [Runtime attribution](javascript-runtime-observation.md), [reconciliation](javascript-runtime-reconciliation.md), [Electron observation](electron-observation.md), [Electron fuses](electron-fuses.md) |
|
||||
| Inspect assemblies, packages, or firmware | [Godot PCK](godot-pck.md), [.NET](managed-code-analysis.md), [Python packages](python-packaged-applications.md), [Android](android-analysis.md), [APK signatures](apk-signature.md), [Apktool resources](apktool-resource-analysis.md), [ADB acquisition](adb-device-analysis.md), [Apple](apple-application-analysis.md), [Harmony](harmony-analysis.md), [firmware](firmware-analysis.md), [WASM](wasm-artifacts.md), [EVM](evm-bytecode.md) |
|
||||
| Observe or compare a browser scenario | [CDP observation](browser-observation.md), [scenarios](browser-scenario-contract.md), [runtime evidence](web-runtime.md), [historical captures](web-network-captures.md) |
|
||||
| Serve recorded behavior as an agent environment | [Agent environments](agent-environments.md) |
|
||||
| Trace captured website source | [Source locations](web-source-location.md), [module traces](website-module-trace.md), [script export](website-script-export.md) |
|
||||
| Capture and compare a command | [Process capture](process-capture.md) |
|
||||
| Use CLI/MCP and retain evidence | [CLI](cli.md), [MCP contracts](mcp-contracts.md), [agent prompts](mcp-prompts.md), [obligation ledgers](reconstruction-obligation-ledgers.md) |
|
||||
|
||||
For development, use [testing](testing.md), [client verification](client-verification.md),
|
||||
[tool design](tool-design.md), and [releasing](releasing.md).
|
||||
[tool design](tool-design.md), [admission limits and recovery](design/limits-and-recovery.md),
|
||||
and [releasing](releasing.md).
|
||||
[Reconstruction readiness](reconstruction-readiness.md) describes a development
|
||||
conformance verifier. [The 6.2 migration](migration-6.2.md) records that release's
|
||||
compatibility changes; [the roadmap](roadmap.md) tracks future work.
|
||||
|
||||
+131
-24
@@ -60,7 +60,10 @@ Before applying changes, REA checks your current configuration. The plan lists:
|
||||
|
||||
Malformed or unsafe existing configuration blocks the whole transaction before
|
||||
Hopper installation or any file write. Declining or pressing Ctrl-C makes no
|
||||
changes. Agent configuration writes preserve unrelated entries and comments,
|
||||
changes. Client configuration files and bundled skill files have separate
|
||||
publication and recovery paths; the guarantees in this paragraph apply to
|
||||
client configuration. See [skill destinations](#skill-destinations) for skill
|
||||
rollback limits. Agent configuration writes preserve unrelated entries and comments,
|
||||
create backups, stage changes in a private directory, and verify their result.
|
||||
Before publication, they refuse detected changes to the selected configuration.
|
||||
Replacement uses an explicit destination under the selected canonical parent;
|
||||
@@ -85,6 +88,11 @@ Setup also retains valid environment overrides in REA's existing server entry,
|
||||
such as `REA_MCP_INPUT_SCHEMA_PROFILE`, `REA_MCP_OUTPUT_SCHEMA_PROFILE`, and
|
||||
`REA_MCP_MAX_RESPONSE_BYTES`.
|
||||
Detected provider settings replace only matching environment keys.
|
||||
Setup manages REA's launcher, selected provider settings, and supported timeout
|
||||
defaults. Client approval policies remain user choices, but the current Codex
|
||||
refresh drops those policies inside the REA entry; see the
|
||||
[Codex preservation limitation](client-configuration.md#codex-and-devin) before
|
||||
refreshing a customized registration.
|
||||
Setup and doctor report a malformed REA environment map or invalid runtime
|
||||
setting before setup writes files. Repair the named setting in the client
|
||||
configuration; setup does not silently discard the rest of the map.
|
||||
@@ -104,9 +112,11 @@ your investigation. Failed steps and diagnostics remain in terminal history.
|
||||
|
||||
Select exact clients in scripts with repeatable `--client` flags. Each explicit
|
||||
client skips interactive selection. Use `--all-detected` only when you intend
|
||||
to configure every detected supported client. `--skill=false` omits the
|
||||
workflow, and `--dry-run` returns a read-only plan with status `planned` and
|
||||
exit code 0:
|
||||
to configure every detected supported client. Combining `--client` with
|
||||
`--all-detected` configures both the explicitly selected and detected clients,
|
||||
even when an explicit client is not detected. Each client is configured once.
|
||||
`--skill=false` omits the workflow, and `--dry-run` returns a read-only plan
|
||||
with status `planned` and exit code 0:
|
||||
|
||||
```bash
|
||||
rea setup --client codex --client cursor --skill=false --dry-run
|
||||
@@ -133,6 +143,15 @@ exits 1. Installing missing Hopper non-interactively additionally requires
|
||||
rea setup --yes --all-detected --install-hopper --json
|
||||
```
|
||||
|
||||
Client configuration writes detect changes to the file read by setup, including
|
||||
when a matching recovery backup already exists. A detected conflict reports
|
||||
`reason: "conflict"` and preserves the newer file; review it and rerun setup.
|
||||
Rollback likewise requires the file identity and content installed by that
|
||||
transaction. Requests for the same resolved path are serialized within one REA
|
||||
process. These checks do not provide an operating-system compare-and-swap or
|
||||
coordinate arbitrary external writers, so avoid editing client configuration
|
||||
while setup is applying it.
|
||||
|
||||
### Skill destinations
|
||||
|
||||
The bundled skill is installed in each selected client's personal skill directory.
|
||||
@@ -151,6 +170,26 @@ paths as `unmanaged`, names the affected paths, and provides those alternatives;
|
||||
an unreadable skill identity remains `unknown`. Uninstall retains and reports
|
||||
files it cannot safely remove, including their ownership manifest.
|
||||
|
||||
The skill installer preserves byte-exact backups of changed existing files,
|
||||
including invalid UTF-8, BOMs, and permission modes, and verifies each published
|
||||
file through its owned descriptor. Before publication it checks the selected
|
||||
file identity; first installation uses an exclusive hard link and refuses a
|
||||
concurrently created destination. Filesystems without hard-link support cannot
|
||||
publish a first-install skill file.
|
||||
|
||||
Rollback restores an existing file only while its published identity, state,
|
||||
and bytes still match that installation attempt. A recovery backup preserves
|
||||
the original bytes; it does not authorize overwriting a later user edit or
|
||||
replacement. Conflicts report the affected paths and recovery backups. If a
|
||||
newly created skill file cannot be verified, setup retains it and reports manual
|
||||
recovery rather than deleting by pathname. Staging cleanup failures remain
|
||||
owned and retryable, and setup does not report installation success while
|
||||
cleanup is unresolved.
|
||||
|
||||
These checks do not lock out another writer modifying the same inode or exclude
|
||||
pathname changes between the last check and publication. Avoid editing managed
|
||||
skill files or running another installer while setup applies them.
|
||||
|
||||
`rea setup --skill-client claude_code --yes --json` refreshes and verifies the
|
||||
selected skill destination independently of MCP registration selection. The
|
||||
final `doctor.scope.skill_clients` records which skill destinations were
|
||||
@@ -402,6 +441,53 @@ symbolic link is retained and reported rather than followed. Uninstall checks
|
||||
REA's managed shared and Claude Code personal skill locations. See the
|
||||
[CLI guide](cli.md#output-and-exit-status) for exit statuses.
|
||||
|
||||
### Missing dependencies in an npx installation
|
||||
|
||||
If REA exits with `ERR_MODULE_NOT_FOUND` before `doctor` can produce a report,
|
||||
inspect the missing path in the error. A path under npm's `_npx/<key>/node_modules`
|
||||
identifies a package-runner installation. In [#5259](https://github.com/morluto/rea/issues/5259),
|
||||
the missing file was `@modelcontextprotocol/client/dist/index.mjs`. That file is
|
||||
present in a clean Windows installation of REA 6.7.0; its absence alone does not
|
||||
establish an incompatible dependency release or explain how the file went missing.
|
||||
|
||||
`npm cache verify` checks npm's downloaded content cache; it does not restore
|
||||
missing files in an already extracted npx installation. Repeating the same npx
|
||||
command can reuse that incomplete installation. To reinstall only the affected
|
||||
entry:
|
||||
|
||||
1. Stop the REA processes and agent clients using that entry. In the same shell
|
||||
environment as the failing command, identify the cache and its entries:
|
||||
|
||||
```powershell
|
||||
npm.cmd config get cache
|
||||
npm.cmd cache npx ls
|
||||
npm.cmd cache npx info REA_CACHE_KEY
|
||||
```
|
||||
|
||||
Replace `REA_CACHE_KEY` with the key from the failing `_npx` path. Check that
|
||||
`info` reports that location and the expected `rea-agents` version. Its
|
||||
`valid` label describes the cache entry metadata, not the presence of every
|
||||
installed file. These subcommands require npm with `cache npx` support.
|
||||
|
||||
2. Remove that specific entry and rerun the affected version with registry
|
||||
access. For the version reported in #5259:
|
||||
|
||||
```powershell
|
||||
npm.cmd cache npx rm REA_CACHE_KEY
|
||||
npx.cmd --yes rea-agents@6.7.0 doctor --json
|
||||
```
|
||||
|
||||
Keep the key argument: this recovery does not require clearing all npm caches
|
||||
or deleting REA configuration, skills, or Evidence. On Linux/macOS, use `npm`
|
||||
and `npx` without `.cmd`. A JSON doctor report confirms startup recovered;
|
||||
it can still exit nonzero for missing analysis engines or registrations.
|
||||
Restart the affected agent after repairing its cache entry.
|
||||
|
||||
If a fresh installation still loses the file, retain the error, REA/Node/npm
|
||||
versions and installation details in the issue. Check installation logs and,
|
||||
on Windows, security software's protection history before attributing the cause.
|
||||
Do not rename `index.cjs` to `index.mjs` or disable protection to make startup pass.
|
||||
|
||||
### Update the owning installation
|
||||
|
||||
`rea update` installs the exact resolved
|
||||
@@ -540,8 +626,10 @@ Hopper is separate commercial software with its own license. Its free demo has
|
||||
vendor-defined limits, and a paid license is optional. REA reuses any detected
|
||||
installation and preserves Hopper during uninstall.
|
||||
|
||||
The automated Hopper installer supports macOS 12+, Ubuntu 24.04+, Fedora 41+,
|
||||
Nobara 44+, 64-bit Arch Linux, CachyOS, or Omarchy. REA itself runs on any
|
||||
The automated Hopper installer supports macOS 12+ and x86_64 hosts running
|
||||
Ubuntu 24.04+, Fedora 41+, Nobara 44+, Arch Linux, CachyOS, or Omarchy. The
|
||||
official Linux packages are x86_64-only, so setup does not offer Hopper on other
|
||||
Linux architectures; configure [Ghidra](#ghidra) there instead. REA itself runs on any
|
||||
Linux distribution with a recognized apt, dnf, or pacman package family, where
|
||||
an existing Hopper launcher is selected through `HOPPER_LAUNCHER_PATH`. Ghidra
|
||||
and IDA have their own provider-specific host requirements; Windows Ghidra uses
|
||||
@@ -636,10 +724,12 @@ manual dependency repair.
|
||||
|
||||
When the package-manager step fails, setup reports the failing command and its
|
||||
captured output, so a package conflict is distinguishable from an authorization
|
||||
failure. On CachyOS, an unversioned compatibility package such as
|
||||
`zlib-ng-compat` may conflict with Hopper's versioned `zlib` dependency. Resolve
|
||||
the package conflict yourself or install Hopper's official package manually,
|
||||
then rerun `rea setup`.
|
||||
failure. Hopper is optional, so setup still applies the approved client
|
||||
registrations and skill, then reports `needs_human` with the Hopper failure. On
|
||||
Arch Linux and CachyOS, the unversioned compatibility package `zlib-ng-compat`
|
||||
may conflict with Hopper's versioned `zlib` dependency. Resolve the package
|
||||
conflict yourself, install Hopper's official package manually, or use another
|
||||
provider such as Ghidra; rerun `rea setup` after installing Hopper.
|
||||
|
||||
The supported Linux demo forwards additional launches into its existing
|
||||
application, even across private displays. REA therefore reserves one Linux
|
||||
@@ -674,7 +764,9 @@ and skips directories.
|
||||
On Linux, it prefers executable `/opt/hopper/bin/Hopper`, then executable
|
||||
`~/.local/share/rea/hopper/bin/Hopper`, followed by `/opt/hopper-v4/bin/hopper`
|
||||
and `/usr/bin/hopper`; if none exists, the former remains the diagnostic
|
||||
fallback. `HOPPER_LAUNCHER_PATH` overrides those choices:
|
||||
fallback. `rea doctor` checks only the current platform's candidates, in the
|
||||
same order; other platforms have no automatic candidates.
|
||||
`HOPPER_LAUNCHER_PATH` overrides those choices:
|
||||
|
||||
```bash
|
||||
export HOPPER_LAUNCHER_PATH=/absolute/path/to/Hopper
|
||||
@@ -923,7 +1015,17 @@ It also checks that the reported JVM `os.arch` and `os.name` map to the same nat
|
||||
directory validated for the host; unrecognized reported architectures or a
|
||||
non-host operating system are refused. LaunchSupport overrides of either
|
||||
property, including through helper-environment JVM option variables, are
|
||||
rejected at launch.
|
||||
rejected at launch. `JDK_JAVA_OPTIONS` argument files (`@file`) are expanded
|
||||
and inspected with that same check using the Java launcher's argfile quoting,
|
||||
comments and continuation rules. The reader admits regular UTF-8 files, retains
|
||||
failed descriptor cleanup, and bounds all admitted file contents and the prepared
|
||||
environment to 64 KiB per launch. Unreadable, oversized or nested `@` references
|
||||
are refused before the analysis JVM starts. Validated bytes are snapshotted under
|
||||
the owned runtime root, so later helpers and the analysis JVM do not reopen mutable
|
||||
caller files. Repeated references share that launch's snapshot; no live state is
|
||||
cached across launches. `JAVA_TOOL_OPTIONS`
|
||||
and `_JAVA_OPTIONS` do not expand `@file` tokens, so they remain
|
||||
literal-token checks.
|
||||
When Java is found through `PATH`, setup records its observed JDK home so GUI
|
||||
MCP clients do not depend on an incidental shell path. Setup shows every exact
|
||||
environment entry in its plan, writes only after approval, and never downloads,
|
||||
@@ -1115,17 +1217,22 @@ override in `analyzer_preset` (for example
|
||||
open when its committed profile and the setting differ. A name starts with a
|
||||
letter or digit and contains only letters, digits, spaces, periods, underscores,
|
||||
and hyphens; at most 32 names are admitted, each at most 120 characters.
|
||||
Names must identify analyzers registered for the selected program. Unknown names
|
||||
or options that remain enabled abort the headless import before auto-analysis
|
||||
and the bridge, so an unsuccessful override cannot produce a session claiming
|
||||
that the analyzer was disabled. The setting applies to every import in the REA
|
||||
server. A format-specific analyzer may not be registered for another target, so
|
||||
the same override can prevent that target from opening. For mixed-target work,
|
||||
omit the override or use a separate REA server configured for the affected
|
||||
format. Changing the environment requires restarting the server; reopening a
|
||||
target alone keeps the current setting. For Windows PE resource analysis, the
|
||||
exact name is `WindowsResourceReference`. Disabling an analyzer skips the facts
|
||||
it would have produced.
|
||||
|
||||
The setting applies to every import in the REA server, but Ghidra registers
|
||||
format-specific analyzers, such as `Objective-C Message Analyzer` or
|
||||
`Demangler Swift`, only for programs they can analyze. A name that the Ghidra
|
||||
installation provides but did not register for the selected program is not
|
||||
applicable: the import continues, the profile still commits the configured
|
||||
names, and result limitations report the applied preset with that name marked,
|
||||
for example `ghidra-default+disabled:Objective-C Message Analyzer(n/a)`. A name
|
||||
that no installed analyzer provides, or an option that remains enabled, aborts
|
||||
the headless import before auto-analysis and the bridge with an error naming
|
||||
`REA_GHIDRA_DISABLED_ANALYZERS` and the analyzer, so a misspelled override
|
||||
cannot produce a session claiming that the analyzer was disabled. Changing the
|
||||
environment requires restarting the server; reopening a target alone keeps the
|
||||
current setting. For Windows PE resource analysis, the exact name is
|
||||
`WindowsResourceReference`. Disabling an analyzer skips the facts it would have
|
||||
produced.
|
||||
|
||||
### Ghidra heap and CPU controls
|
||||
|
||||
@@ -1292,7 +1399,7 @@ equivalent entry point. Setup run through `npx` registers
|
||||
`cmd.exe /d /c` so clients can start the runner's command shim. Neither
|
||||
registration points into the runner's temporary package cache.
|
||||
|
||||
REA supports Node.js 22.x (>=22.19), 24.x (>=24.11), and 26+. Node.js 23, 25, and prereleases are unsupported. It uses the npm already paired with that runtime and never upgrades Node.js, npm, or Homebrew.
|
||||
REA supports Node.js 22.x (>=22.23.4), 24.x (>=24.22.1), and 26.12.1+. Node.js 23, 25, earlier 26.x releases, and prereleases are unsupported. It uses the npm already paired with that runtime and never upgrades Node.js, npm, or Homebrew.
|
||||
|
||||
When REA runs on Bun, the `rea doctor` `node` check reports the Bun version and
|
||||
the Node.js compatibility version Bun declares, and passes when that
|
||||
|
||||
@@ -80,8 +80,8 @@ Graph coverage describes the analyzed artifact scope and resource limits, not
|
||||
runtime execution. A partial target alone does not imply omitted source.
|
||||
|
||||
The directed relation vocabulary is `contains`, `loads`, `imports`, `maps_to`,
|
||||
`exposes`, `sends`, `invokes`, `handles`, `calls`, `persists_to`, `observed_as`,
|
||||
and `changed_from`. Provider names are deliberately absent from both
|
||||
`exposes`, `sends`, `invokes`, `handles`, `calls`, `accesses`, `persists_to`,
|
||||
`observed_as`, and `changed_from`. Provider names are deliberately absent from both
|
||||
vocabularies.
|
||||
|
||||
For a `maps_to` edge targeting a source-map node, the edge carries
|
||||
|
||||
@@ -40,6 +40,12 @@ combine its fields with the fact's location. Semantic trace results include the
|
||||
canonical context subset referenced by their returned facts, so those facts
|
||||
remain self-contained in the response.
|
||||
|
||||
Content-deduplicated module references match every retained observation path.
|
||||
A path-filtered reference reports the caller-selected path while keeping its
|
||||
shared node identity. Item selection also accepts any retained path when it
|
||||
identifies one module; if several module kinds share that path, select the
|
||||
reported `node_id`. Node-ID selection uses the stable representative path.
|
||||
|
||||
## Retained module facts
|
||||
|
||||
For canonical identities and retained source-range counts, query the existing
|
||||
@@ -183,6 +189,11 @@ registrations/removals and dispatch, Node timers and cancellation handles, async
|
||||
`node:child_process` creation and ownership, configuration sources and direct
|
||||
defaults, request construction and response consumers, parse/coercion/
|
||||
validation boundaries, and built-in resource acquisition/release.
|
||||
Global timer, `fetch`, `WebSocket`, `JSON.parse`, and coercion calls receive
|
||||
these built-in effects only when the file has no visible possible write to that
|
||||
global, including a computed write through a global object. The check does not
|
||||
evaluate order or reachability, so a later or guarded polyfill write also
|
||||
removes the resolved effect.
|
||||
|
||||
Local callback candidates do not establish a complete target set when a
|
||||
conditional write may leave a parameter, catch binding, or uninitialized
|
||||
@@ -401,8 +412,23 @@ when the object is an array element, nested inside mixed object/array
|
||||
containers, or assigned to a previously declared identifier. Saving the getter
|
||||
result in an alias does not make its old field values immutable. Known array
|
||||
indices include holes; an element after a spread has only a minimum possible
|
||||
index. Unrelated properties and known array prefixes remain precise, and a
|
||||
getter read without a write does not invalidate the receiver's fields.
|
||||
index. For these returned-reference writes, unrelated properties and known
|
||||
array prefixes remain precise. Accessor applicability uses the shared object
|
||||
reference owner for literal definition order, own-property shadowing, known
|
||||
array elements and explicit literal prototypes. Getter invocation effects
|
||||
project write and call operands through the same local alias and `this` owner
|
||||
used by returned references. Reads of another selected getter continue that
|
||||
effect walk. A receiver reached by these effects becomes uncertain on an
|
||||
ordinary or optional read, compound assignment or update. A simple assignment
|
||||
or deletion does not invoke the getter. Selected setters invalidate
|
||||
the receiver on assignment, including through known array and prototype paths.
|
||||
Inert getters and ordinary data slots retain their supported precision.
|
||||
|
||||
These are conservative source-derived effects, not execution results. The
|
||||
analysis does not establish general accessor purity, model every class or
|
||||
reflectively installed descriptor, or cover getter reads introduced by object
|
||||
spread/destructuring and all implicit coercion or disposal invocations. Absence of a later explicit write does not establish getter purity;
|
||||
unsupported invocation forms can still retain stale receiver-field facts.
|
||||
Nested callable returns are not assigned to their parent callable. Projected
|
||||
graph observations carry source ranges but never source text.
|
||||
|
||||
|
||||
@@ -106,6 +106,18 @@ only reduces delivery; source selection reduces text acquisition and analysis.
|
||||
Explicit native provider or snapshot routing rejects `--source-path` rather
|
||||
than ignoring it.
|
||||
|
||||
ASAR header/index admission defaults to 16 MiB / 16777216 bytes. Set
|
||||
`REA_ASAR_MAX_HEADER_BYTES` in the environment that starts REA to a decimal
|
||||
byte count of at most 268435456 (256 MiB) to raise or lower it; restart REA
|
||||
after changing it. Invalid values are configuration errors, never a silent
|
||||
fallback. The archive index is read before any member can be selected, so
|
||||
`source_paths`, `--source-path`, `detail: "summary"`, `max_heap_mb`, and
|
||||
available host memory do not bypass or raise it. When the header exceeds the
|
||||
effective allowance, the failure names it, whether it came from the default or
|
||||
the setting, and the setting's limits. Alternatively, analyze an extracted
|
||||
application directory, which does not admit an ASAR header. Repeating the unchanged
|
||||
request fails the same way.
|
||||
|
||||
## Read the analysis
|
||||
|
||||
`analyze_javascript_application` returns the complete analysis Evidence by
|
||||
@@ -172,7 +184,8 @@ for the tool-result contract.
|
||||
|
||||
Use MCP `detail: "summary"` for a large application, then read selected views of
|
||||
the retained analysis. Summary changes delivery only. To reduce source parsing,
|
||||
select exact [source paths](#select-sources-before-analysis).
|
||||
select exact [source paths](#select-sources-before-analysis). Source selection
|
||||
does not bypass ASAR header/index admission.
|
||||
|
||||
If a complete response exceeds the transport budget, use its retained Evidence
|
||||
ID for a summary, module page, or item, or export the bundle. See
|
||||
@@ -239,7 +252,8 @@ Selected bounded text is then parsed as inert data to recover:
|
||||
- Electron preload paths and renderer files visible in static syntax;
|
||||
- local HTML script entrypoints;
|
||||
- Webpack and Rspack chunk registrations and module factories represented as
|
||||
AST literals;
|
||||
AST literals, plus esbuild `__commonJS` module tables; recovered esbuild
|
||||
CommonJS exports use its factory's `exports`-then-`module` parameter order;
|
||||
- static imports, dynamic imports, CommonJS `require` calls, workers, and
|
||||
service workers (only `new Worker(new URL(path, import.meta.url))` resolves
|
||||
relative to the calling module; string worker and service-worker paths use
|
||||
@@ -379,6 +393,11 @@ observation, because callers outside the traced paths may pass other values.
|
||||
A wrapper call that is both its own entry and reached through another entry
|
||||
is recorded once when both paths find the same facts; calls that supply
|
||||
different handlers or channels stay distinct.
|
||||
A contextBridge exposure reached through wrapper calls records one API per key
|
||||
those invocations supply, each with its own bounded member paths. Invocations
|
||||
that supply the same key to one exposure call describe one API covering each
|
||||
alternative object. A traced invocation whose key, API object or world stays
|
||||
unresolved or guarded keeps the call's own unresolved observation.
|
||||
Unknown spreads, reassigned bindings, accessors,
|
||||
dynamic channels and unsupported syntax do not become exact implementations.
|
||||
This pass neither executes the bundle nor proves that runtime guards pass.
|
||||
@@ -495,6 +514,11 @@ inventory digest before parsing, and malformed ASAR operations return typed
|
||||
format diagnostics that retain the local container path. Native add-ons are
|
||||
represented by metadata only.
|
||||
|
||||
POSIX directory names are read as raw bytes and admitted as logical paths only
|
||||
when they round-trip through UTF-8. Invalid names are left untouched, retained
|
||||
siblings remain inventoried, and traversal coverage is marked unknown with the
|
||||
first rejected basename bytes identified in hexadecimal.
|
||||
|
||||
## Bounds and coverage
|
||||
|
||||
The reconstruction keeps internal resource safeguards for artifact entries,
|
||||
@@ -618,6 +642,13 @@ execution and memory limits continue to determine examined coverage. Raising onl
|
||||
a node capacity does not raise the unknown capacity. Graphs without unknown
|
||||
omissions omit this optional coverage field, preserving their existing identities.
|
||||
|
||||
These node and unknown capacities bound retained graph projection. Parsing,
|
||||
static analysis and semantic fact construction precede that projection for an
|
||||
admitted source. Lowering the capacities can reduce projection and retention
|
||||
work, but does not bound upstream semantic-analysis time or memory. Select fewer
|
||||
`source_paths` to reduce the sources analyzed; heap and deadline controls set
|
||||
separate resource failure boundaries with the runtime-specific limits above.
|
||||
|
||||
While sources remain, the sequential worker reserves one next compact static
|
||||
checkpoint at its 8 MiB bound with the same 6x retention expansion used at
|
||||
admission. Earlier checkpoints are already charged to retained bytes; the
|
||||
@@ -738,6 +769,24 @@ URL targets before selecting a later package-local file; an unsupported bare
|
||||
package or recursive alias keeps its unresolved outcome rather than selecting
|
||||
a later fallback.
|
||||
|
||||
For a proven `createRequire(new URL(relativeFile, import.meta.url))` call,
|
||||
relative `require()` edges use the selected filename's directory and retain the
|
||||
source-relative `resolution_base_path` on the graph edge. This follows Node's
|
||||
`createRequire(filename)` contract; the path is a loader-resolution fact and
|
||||
does not change the source file or call-site Evidence identity. If the filename
|
||||
cannot be proven, REA keeps the require target unresolved rather than silently
|
||||
resolving it from the caller's directory.
|
||||
|
||||
Module-reference graph edges, including native-addon `loads` edges, retain
|
||||
`properties.operation`: `load` identifies
|
||||
an import or loader invocation that may execute the target; `resolve` identifies
|
||||
a proven `require.resolve()` lookup that discovers a target without executing it.
|
||||
Both retain the exact specifier, resolution mode, selected resolution base, and
|
||||
call-site Evidence. Resolve-only edges do not propagate application ownership or
|
||||
create executable-import gaps when their targets are missing. A modified
|
||||
`.resolve` member remains an uncertain `load`, because its replacement may execute
|
||||
code. These static facts do not establish that a call runs at runtime.
|
||||
|
||||
ESM relative module paths, legacy package subpaths without exports, and selected
|
||||
package exports targets use URL suffix handling and one percent-decoding pass.
|
||||
Bare specifiers retain their complete query/fragment text for exports key matching.
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
# Static JavaScript route inventory
|
||||
|
||||
`analyze_javascript_application` and `analyze_web_bundle` retain a shared
|
||||
`route_inventory` alongside their existing graph and endpoint observations.
|
||||
The inventory answers which route patterns the supplied code suggests, where
|
||||
each pattern came from, and which parts remain unknown. It never requests a
|
||||
route, executes scripts, expands a sitemap, or establishes reachability.
|
||||
|
||||
Select a compact view in either MCP analysis call:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "summary",
|
||||
"view": {
|
||||
"kind": "javascript-routes",
|
||||
"collection": "routes",
|
||||
"where": { "path_prefix": "/reports" },
|
||||
"fields": ["path", "classification", "confidence"],
|
||||
"limit": 20
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Keep the original analysis inputs in that call. For the CLI, pass the same
|
||||
selection as `--view '<JSON>' --detail summary --evidence_output routes.json`.
|
||||
The complete Evidence bundle is written without overwriting existing files.
|
||||
Unselected delivery retains the existing complete result. A web-bundle summary
|
||||
requires an explicit route view; application summaries also support the existing
|
||||
general summary when `view` is omitted.
|
||||
|
||||
Use the returned `normalized_result.parent_evidence_id` with
|
||||
`inspect_analysis_view` on the same connection. The CLI's exported bundle can be
|
||||
reopened with `inspect-evidence-bundle`; its `records` contain the complete
|
||||
Evidence. To use `inspect_analysis_view`'s `evidence-file` source, extract the
|
||||
selected parent record into a separate local Evidence JSON file (that source
|
||||
accepts one Evidence record, not a bundle). Views do not reopen source files or
|
||||
reconnect to a browser. Historical Evidence without `route_inventory` is
|
||||
unmeasured, rather than an empty route set.
|
||||
|
||||
Collections are `summary`, `routes`, `occurrences`, `sources`, and `unknowns`.
|
||||
All row collections support exact batch `where.ids`, field selection, `offset`,
|
||||
and `limit`. An explicit empty filter array matches nothing. Routes also support
|
||||
exact `paths`, literal `path_prefix`, `classifications`, `mechanisms`, and
|
||||
`min_confidence`; occurrences support `route_ids`, `source_ids`, and `mechanisms`;
|
||||
sources support `keys` and `statuses`; unknowns support `source_ids` and `kinds`.
|
||||
Follow `coverage.next_offset` until `coverage.exhausted`; a page may stop early
|
||||
at the 1 MiB serialized view budget. Oversized indivisible facts return a
|
||||
resource error carrying the retained parent Evidence ID.
|
||||
|
||||
Pattern IDs bind the exact path. Source IDs bind the source key, path, original
|
||||
URL, content digest and container digest. Occurrences identify a detector mechanism at a source location; one location
|
||||
may support multiple mechanisms. `source_count` counts distinct sources. Lookup IDs use 128 bits of SHA-256;
|
||||
full content and inventory digests remain SHA-256. Field selection always keeps
|
||||
row identity and necessary provenance. The page's deduplicated `sources` table
|
||||
contains the source descriptors referenced by returned rows. Retrieve all
|
||||
occurrences by route ID when independent supporting evidence matters. Source
|
||||
ranges use one-based lines and zero-based UTF-16 columns with exclusive ends;
|
||||
filename-only discoveries have no invented AST range.
|
||||
|
||||
The shared parser handles literal router calls, nested route objects, typed
|
||||
`_$` trees with explicitly inferred property-name fallbacks, Next App Router
|
||||
page paths, and navigation targets. It follows stable lexical bindings and
|
||||
keeps unresolved parents, mutations, spreads, and dynamic fields explicit.
|
||||
A selected route-builder root owns its configuration even when mutation prevents
|
||||
trusting its value. Ordinary wrapper keys do not become route ancestors. Missing
|
||||
outer ancestors of unbound typed subtrees remain unknown rather than invented.
|
||||
Generic Next runtime path constants require a top-level application segment
|
||||
supported by structural or navigation candidates across the supplied sources.
|
||||
This limits framework filesystem noise, while leaving unsupported candidates
|
||||
unknown. The parser shares the existing AST traversal and lexical index.
|
||||
|
||||
[Next dynamic segments](https://nextjs.org/docs/app/api-reference/file-conventions/dynamic-routes)
|
||||
map to `:id`, `:slug+`, or `:slug*`; groups and parallel slots do not contribute
|
||||
URL segments. Intercepted routes remain unresolved. A prefix before `/_next/`
|
||||
is an **inferred** routing base: [assetPrefix](https://nextjs.org/docs/app/api-reference/config/next-config-js/assetPrefix)
|
||||
can differ from the routing base. Every affected occurrence keeps
|
||||
`unprefixed_path`, `inferred_base_path`, and low confidence. `system` classification
|
||||
is explicitly a path-name heuristic; `page` uses page-file or structured/typed configuration support. Name-only
|
||||
`route`/`addRoute` calls remain `unknown` because they can also register server APIs.
|
||||
|
||||
Next page-source segments keep their filename spelling when converted to route
|
||||
patterns. Next's [page-path conversion](https://github.com/vercel/next.js/blob/v16.4.2/packages/next/src/shared/lib/page-path/absolute-path-to-page.ts#L21-L39)
|
||||
removes page extensions and the `index` tail without URI-decoding segments, so
|
||||
ordinary percent sequences are not decoded: `%61` and `a` remain separate
|
||||
candidates and a literal `%` is retained. Its [App pathname normalizer](https://github.com/vercel/next.js/blob/v16.4.2/packages/next/src/server/normalizers/built/app/app-pathname-normalizer.ts#L5-L18)
|
||||
specifically applies the [underscore normalizer](https://github.com/vercel/next.js/blob/v16.4.2/packages/next/src/server/normalizers/underscore-normalizer.ts#L2-L9),
|
||||
which maps `%5F` to `_`; private-folder checks apply to the source spelling
|
||||
before that escape is mapped. When classifying a chunk URL, REA reads its
|
||||
pathname, then applies these same Next-specific rules. This is static source-path
|
||||
interpretation, not browser request-path decoding or reachability.
|
||||
|
||||
Known capture omissions remain inline in `summary.reported_capture_omissions`
|
||||
and queryable as `unknowns` of kind `capture-omission`. Each keeps a stable gap ID,
|
||||
its script-record/script-source unit, and the reported count (including `null`
|
||||
for unknown). They do not invent missing script identities or source ranges.
|
||||
|
||||
Counts describe deduplicated patterns in the provided code sources. They are
|
||||
not a denominator for complete application or capture coverage. In particular,
|
||||
server-only, lazy, inaccessible, or unselected sources may be missing.
|
||||
`coverage.application_routes` always remains `unknown`; parsing and candidate
|
||||
enumeration have their own completeness. Static work and fact admission share
|
||||
the existing 8 MiB per-source transfer ceiling, and the root inventory has an
|
||||
8 MiB admission budget. Exhaustion preserves a prefix with explicit capacity;
|
||||
the serialization owner also admits route facts within the actual space left by
|
||||
legacy facts. `result-bytes` capacity preserves an earlier work-capacity reason;
|
||||
if even that envelope cannot fit, the optional route facet remains unmeasured.
|
||||
These are accounting bounds, not a claim that total process memory is 8 MiB.
|
||||
|
||||
Projection only reduces delivery, not analysis work. Retained immutable Evidence
|
||||
can reuse validated tables through a weak cache with the snapshot's lifetime;
|
||||
subject identity is checked on every query. No live state or source content is
|
||||
cached as current. Use existing source selection and resource controls when
|
||||
they match the investigation, keeping their partial coverage visible.
|
||||
@@ -105,7 +105,9 @@ The direct observations are:
|
||||
- `Debugger.scriptParsed`, establishing that a bounded script location was
|
||||
parsed in the observed execution context;
|
||||
- `Debugger.scriptFailedToParse`, retained only as a bounded invalid-script
|
||||
count;
|
||||
count in `scripts.parse_failed_total`. A well-formed parse-failure
|
||||
event is distinct from malformed protocol data and does not make loaded
|
||||
script coverage unavailable. Older Evidence may omit this count;
|
||||
- `Runtime.executionContextCreated`,
|
||||
`Runtime.executionContextDestroyed`, and
|
||||
`Runtime.executionContextsCleared`, establishing context lifecycle within
|
||||
@@ -119,6 +121,12 @@ handlers, or script-unload events. Those facts remain explicit unknowns.
|
||||
`scriptParsed` proves script presence, not the importing module, feature
|
||||
execution, initialization order, or causality.
|
||||
|
||||
For an authorized file script, `location.file_path` is the verified filesystem
|
||||
identity and optional script-item `reported_url` preserves the exact Inspector
|
||||
URL. Script identity includes that reported URL, so query and fragment
|
||||
variants of one file remain separate observations. Older Evidence may omit
|
||||
`reported_url` and remains readable.
|
||||
|
||||
## Node and Electron roles
|
||||
|
||||
The caller declares one role: `node`, `electron-main`, `electron-preload`, or
|
||||
|
||||
@@ -57,7 +57,11 @@ are complete Evidence objects, not only evidence IDs:
|
||||
`static_layers` requires exactly one `application` role and permits additional
|
||||
`cache` and `assets` roles. A `file-root` mapping translates a canonical runtime
|
||||
filesystem root to an artifact-relative prefix. A `url-prefix` mapping does the
|
||||
same for one exact HTTP(S) origin and path prefix. Mappings cannot add CDP
|
||||
same for one exact HTTP(S) origin and path prefix. Each URL path segment below
|
||||
the prefix is percent-decoded separately: an encoded slash (`%2F`) stays inside
|
||||
its segment and never names a nested artifact, so such a location, like one
|
||||
with malformed or non-UTF-8 escapes, has no artifact path under that mapping.
|
||||
An encoded backslash (`%5C`) remains a literal name byte. Mappings cannot add CDP
|
||||
origins, broaden Electron roots, read files, or authorize source-map access;
|
||||
they are caller-declared inference inputs applied only to already-authorized
|
||||
locations.
|
||||
@@ -106,7 +110,12 @@ nodes. REA evaluates compatible static candidates conservatively:
|
||||
that disagreement. If a mapped candidate's digest is unavailable and no
|
||||
mapped content match is known, the comparison remains `unknown`.
|
||||
6. Missing authorization mappings and incomplete or truncated input coverage
|
||||
remain unknown or truncated rather than becoming absence claims.
|
||||
remain unknown or truncated rather than becoming absence claims. A runtime
|
||||
location with no automatic artifact-root or caller-declared mapping into
|
||||
any layer, and no content match, is `unknown` with
|
||||
`no-authorized-location-mapping`, with or without captured bytes; several
|
||||
content matches remain `ambiguous` under rule 4. Only a mapped location can
|
||||
be `unmatched` with `no-static-content-match`.
|
||||
|
||||
Every successful cross-layer `observed_as` edge has
|
||||
`authority: cross-layer-reconciliation` and `state: inferred`. The underlying
|
||||
@@ -128,6 +137,8 @@ classification:
|
||||
- `unknown` covers incomplete captures, layers outside runtime scope, and
|
||||
unresolved correspondence. Nodes outside a mapped artifact prefix stay
|
||||
unknown even when another prefix in the same static layer was observed.
|
||||
Nodes beneath a mapped artifact prefix also stay unknown when a runtime
|
||||
script or worker under that mapping has no artifact path.
|
||||
|
||||
None of these states proves feature execution, initialization order,
|
||||
reachability, or causality. In particular, `not-observed-in-capture` never means
|
||||
|
||||
@@ -42,7 +42,7 @@ reaches its budget returns a typed timeout naming the phase and the effective
|
||||
milliseconds, while caller cancellation remains a cancellation. Allow execution,
|
||||
cleanup, and delivery headroom in the outer MCP client deadline.
|
||||
|
||||
Earlier verification used JEB 5.48.0 (Linux x64, licensed build) serving `jeb-mcp-server` 1.3.0 over streamable HTTP. The official Linux x64 CE build `5.48.0.202610071539` was also verified through real CLI and production stdio MCP native-code workflows; see the [Linux CE audit](../experiments/analysis-efficiency/jeb-linux-native.md) for measurements and limits. CE verification does not establish licensed/Demo Android decompilation or GUI behavior.
|
||||
Earlier verification used JEB 5.48.0 (Linux x64, licensed build) serving `jeb-mcp-server` 1.3.0 over streamable HTTP. The official Linux x64 CE build `5.48.0.202610071539` was also verified through real CLI and production stdio MCP native-code workflows; see the [Linux CE audit](https://github.com/morluto/rea/blob/42e1a17d6e6c0487f17be0bae248553c4caba7f7/experiments/analysis-efficiency/jeb-linux-native.md) for measurements and limits. CE verification does not establish licensed/Demo Android decompilation or GUI behavior.
|
||||
|
||||
## Operations
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ The background export belongs to the session. `close_binary`, or the end of a CL
|
||||
|
||||
The assembly label index is scanned once per export reader. Cancelling a request stops its wait without interrupting other readers; closing the session aborts and drains the shared scan before releasing its files.
|
||||
|
||||
Regex procedure and string search uses ECMAScript Unicode matching in a cancellable worker with a five-second matching deadline and a 128 MiB worker heap. Literal matching remains the default. Cancellation or a matching deadline leaves the session available. This release has no runtime override for that deadline or heap.
|
||||
Regex procedure and string search uses ECMAScript Unicode matching in a cancellable worker with a matching deadline and a worker old-generation heap. Literal matching remains the default. Cancellation or a matching deadline leaves the session available. The deadline is `REA_REGEX_MATCHING_DEADLINE_MS`, a positive decimal integer from 1 to 2147483647 ms. Unset uses 5000 ms. A larger value is refused because Node schedules a delay past that signed 32-bit bound as 1 ms. Invalid values are configuration errors and do not fall back to the default. The setting is read from the environment that starts REA, so a change needs a restart. A deadline failure names the effective milliseconds, whether they came from the default or the setting, the default, and the maximum. The worker old-generation heap does not raise it. The worker heap request is `REA_REGEX_WORKER_HEAP_REQUEST_MIB`, a decimal integer from 7 to 16384 MiB. Unset uses 128 MiB. A request below 7 MiB aborts the worker during startup, and a larger value is refused. Invalid values are configuration errors and do not fall back to 128. The setting is read from the environment that starts REA, so a change needs a restart. A heap failure names the effective request, whether it came from the default or the setting, the default, the floor, and the maximum. A positive Node.js `--max-old-space-size` on the process that starts REA, including `NODE_OPTIONS`, overrides that request and sets the effective heap. `--max-old-space-size-percentage` takes precedence over that flag in either order. REA does not turn the percentage into a MiB, so the effective heap stays unestablished instead of the worker heap request or the absolute flag. The reported `NODE_OPTIONS` value is the process initial environment when that block can be read. A later edit to the environment is not the value Node applied, and an unreadable initial value leaves the effective heap unestablished. The launch Node options are the initial command line on Linux when that buffer still has a program entry, not a later edit to `process.execArgv`. A preload can clear that array after V8 has applied the flags. Setting `process.title` or `--title` overwrites the command line, so a buffer without a program entry leaves the effective heap unestablished. `--env-file` or `--env-file-if-exists` can supply `NODE_OPTIONS` when the initial environment has none. That file is not part of the initial environment block, so the effective heap stays unestablished instead of the worker heap request. An initial `NODE_OPTIONS` is still used, because Node does not let the file replace it. A positive `--max-heap-size`, including the underscore form and launch `NODE_OPTIONS` on Node versions that allow it, sets the total heap rather than the old generation and can be lower than the worker heap request. The effective old generation stays unestablished while that value is in effect. A zero or empty value clears it. `--experimental-config-file` or `--experimental-default-config-file` can set `nodeOptions`, including a heap percentage, from a file that is not read back. The effective heap stays unestablished when either flag is present, including when an absolute `--max-old-space-size` is also on the command line or in the recovered `NODE_OPTIONS`. Node accepts the config path as `=` or the next argument.
|
||||
|
||||
Single-function subprocess output and each cached source facet share a 16 MiB buffered-text capacity. Cached spans are checked before allocation; larger text remains in the local export and the error identifies the file and range. `analyze_function` initially returns the complete dossier, which can still be large; later retained views do not remove that first transfer. Prefer the individual text tools for a focused question.
|
||||
|
||||
|
||||
@@ -51,6 +51,11 @@ This keeps the complete source in the session and returns a distinct linked
|
||||
evidence, metadata status, module/MVID, assembly, frameworks, returned-row counts,
|
||||
coverage/issues and limitations. No assembly is loaded or executed.
|
||||
|
||||
ECMA-335 permits empty metadata streams to be omitted. An absent `#Blob`
|
||||
stream therefore does not prevent module or assembly identity from being read
|
||||
when all blob indexes are zero; a nonzero reference to that missing heap is
|
||||
reported as a missing-stream issue.
|
||||
|
||||
Use `normalized_result.parent_evidence_id` to page original rows:
|
||||
|
||||
```json
|
||||
@@ -85,7 +90,7 @@ rejects selected summary before analysis; complete delivery remains available.
|
||||
|
||||
Complete `inspect_managed_members` delivery always includes the assembly-wide
|
||||
`member_refs` and `exported_types`, which `type_names` does not narrow, so even
|
||||
one selected or unmatched type can return megabytes. Select
|
||||
one selected or unmatched type can return megabytes. In MCP, select
|
||||
`{"path":"/absolute/path/Assembly.dll","type_names":["Namespace.Type"],"detail":"summary"}`
|
||||
to keep the complete source in the session and receive identity, metadata
|
||||
status, the selection with its unmatched names, coverage/issues, the separate
|
||||
@@ -115,6 +120,49 @@ literal pool's own coverage. Older Evidence that never examined exported types
|
||||
or user strings reports a null count and refuses those pages rather than
|
||||
returning an empty one.
|
||||
|
||||
#### CLI summary and saved member rows
|
||||
|
||||
The CLI accepts the same `complete` and `summary` detail choices. Omitted or
|
||||
`--detail complete` returns complete Evidence. To receive a summary, choose a
|
||||
new Evidence bundle destination so its original complete parent remains
|
||||
available after the command exits:
|
||||
|
||||
```bash
|
||||
rea inspect-managed-members /absolute/path/Assembly.dll --type Namespace.Type \
|
||||
--detail summary --evidence-bundle /absolute/path/evidence/members.json --json
|
||||
```
|
||||
|
||||
`--evidence-bundle` writes the complete original Evidence in REA's canonical
|
||||
bundle format. Its parent directory must exist, and it never replaces an
|
||||
existing path. Relative paths resolve against the command's working directory.
|
||||
The option also works with complete delivery when a saved bundle is useful.
|
||||
Summary without a destination is rejected before analysis. A publication failure
|
||||
returns a typed error with the completed Evidence under
|
||||
`details.partial_observation`; it does not report successful summary delivery.
|
||||
Cancellation before publication prevents the new output. Once atomic
|
||||
publication has started, it can complete despite cancellation; a cancelled
|
||||
delivery then retains the committed path and byte count under
|
||||
`details.diagnostics.evidence_bundle`.
|
||||
|
||||
Copy `normalized_result.parent_evidence_id` from the summary into the
|
||||
`source.evidence_id` field of the `managed-members` request above, then save that
|
||||
small request as `members-page.json` and run:
|
||||
|
||||
```bash
|
||||
rea inspect-analysis-view /absolute/path/evidence/members-page.json \
|
||||
--evidence-bundle /absolute/path/evidence/members.json --json
|
||||
```
|
||||
|
||||
The view command authenticates the selected bundle and resolves that exact
|
||||
parent ID. It does not reopen the assembly, so the original target may have
|
||||
been moved or removed. Subsequent calls can select another collection or use
|
||||
the returned `coverage.next_offset` to continue the same collection. An inline
|
||||
source already includes its parent and cannot also select `--evidence-bundle`.
|
||||
|
||||
Summary changes delivery, while type selection still controls decoding and the
|
||||
same inspection resource limits apply. Each separate CLI page reads and
|
||||
authenticates the saved bundle; the full source is retained on disk.
|
||||
|
||||
## Shipped scope
|
||||
|
||||
The canonical parser admits PE/CLI bytes and their metadata/CIL without loading
|
||||
@@ -134,6 +182,9 @@ declares API compatibility across multiple .NET implementations. REA preserves
|
||||
that target in `target_frameworks` and leaves `runtime_family` as `unknown`
|
||||
unless independent markers identify a runtime family, such as a ReadyToRun
|
||||
signature.
|
||||
When ReadyToRun is observed, `runtime_family` remains `modern-dotnet` even if
|
||||
Unity or target-framework hints are also present; the separate hint evidence
|
||||
is retained in the classification evidence list.
|
||||
|
||||
### Resource admission
|
||||
|
||||
@@ -157,8 +208,19 @@ rather than interpreted according to section order.
|
||||
|
||||
### Selected member inspection
|
||||
|
||||
When whole-assembly member decoding reaches the representation budget, select
|
||||
known declaring types before their signatures and CIL bodies are decoded:
|
||||
Member inspection admits type names, tokens, list ranges/counts, nesting facts,
|
||||
module identity and their output representation before decoding members. If
|
||||
later decoding or projection reaches the 64 MiB representation budget, the
|
||||
result retains this type inventory with `coverage.state: "partial"` and the
|
||||
original `resource-limit` coordinate. It does not return partially admitted
|
||||
member collections: empty fields, methods, references and edges are unexamined,
|
||||
not proof of absence; exported types, user strings and signature-resolution
|
||||
attestation remain null. Summary and retained pages keep this partial coverage.
|
||||
The capacity limit is unchanged. If metadata or the type inventory itself cannot
|
||||
be admitted, the result remains unavailable.
|
||||
|
||||
Use the returned `types[].full_name` values to select declaring types before
|
||||
their signatures and CIL bodies are decoded:
|
||||
|
||||
```bash
|
||||
rea inspect-managed-members /absolute/path/Assembly.dll --type Example.Parser
|
||||
@@ -188,7 +250,21 @@ remain an assembly-wide inventory, so output size is not guaranteed to be small.
|
||||
Coverage describes the selected members. Comparisons leave members outside the
|
||||
opposite observation's selection unknown, and application graphs report their
|
||||
selected scope as partial. Neither makes an absence claim about the whole
|
||||
assembly. Older member Evidence without `selection` remains readable.
|
||||
assembly. Older member Evidence without `selection` remains readable. The
|
||||
`method_rows` interval records the examined zero-based MethodDef offset, row
|
||||
count and full table total before type selection. A complete observation can
|
||||
cover only that interval. Comparison keeps omissions from a method page unknown:
|
||||
build-local row positions cannot prove member absence across builds. Historical
|
||||
Evidence without this interval also cannot establish method absence; observed
|
||||
pairs and field inventory comparisons remain available.
|
||||
|
||||
For MCP callers, request `detail: "summary"` and page the `types` collection
|
||||
using the returned parent Evidence ID. Select one or more returned full names
|
||||
in a subsequent `inspect_managed_members` request. Selection is a recovery path,
|
||||
not a guarantee: a single type or the assembly-wide member references can still
|
||||
exhaust the representation budget. A successful command exit means the Evidence
|
||||
was returned; inspect `coverage.state` and `coverage.issues` before treating any
|
||||
collection as complete.
|
||||
|
||||
### User strings
|
||||
|
||||
@@ -249,6 +325,19 @@ native/runtime questions retain their own authority and coverage.
|
||||
|
||||
## Member comparison
|
||||
|
||||
Call edges and field accesses retain `il_offset` as their instruction site within
|
||||
the caller's build-local method token and artifact identity. Their
|
||||
`target_identity_sha256` combines the existing enclosing-type nominal digest,
|
||||
member name and resolved decoded signature. Comparison joins edges to their
|
||||
instruction sites rather than array positions and compares these identities;
|
||||
display labels alone cannot establish equal targets. Same-named nested types
|
||||
under different enclosing types and different overload signatures stay distinct.
|
||||
This is nominal metadata identity, not assembly resolution or runtime binding.
|
||||
Historical edges without a site or identity, unresolved/cyclic type scopes,
|
||||
TypeSpec owners and unresolved MethodSpec instantiations retain unknown target
|
||||
equivalence. Valid MethodSpecs combine the base member identity with the
|
||||
resolved instantiation signature, preserving generic argument distinctions.
|
||||
|
||||
Names and semantic labels do not establish durable member identity. Comparison
|
||||
preserves observed differences, structural inferences, and unknowns separately.
|
||||
|
||||
@@ -324,6 +413,24 @@ constants, and bounded shape context. It reports all candidates at the winning
|
||||
score and remains ambiguous when the evidence does not distinguish them. The
|
||||
digest does not itself remap metadata tokens.
|
||||
|
||||
Matched methods also compare aligned references. `call-shape` and
|
||||
`field-shape` report opcode and operand-kind differences; `call-target` and
|
||||
`field-target` report differences in the observed target declaring type or
|
||||
name from `call_edges` and `field_accesses`. Target tokens remain build-local
|
||||
and are not compared across artifacts. Missing or unaligned edges and missing
|
||||
target names leave that facet unknown; equal names do not establish overload
|
||||
identity or runtime dispatch. `exception-shape` compares clause flags and
|
||||
ranges. `exception-target` compares the nested nominal catch-type name digest;
|
||||
for resolved TypeDefs it also compares the enclosing assembly identity. A
|
||||
different known name or assembly scope establishes a change. Equal TypeRef
|
||||
names remain unknown because their resolution scope is not resolved here.
|
||||
Exception tokens remain in the source facts but are not cross-build identity;
|
||||
an unresolved catch type leaves that facet unknown. The method body retains the
|
||||
display `class_type`, nested `class_type_name_sha256`, and whether its local
|
||||
token identifies a TypeDef. A TypeDef digest alone does not prove identity
|
||||
without matching assembly identity. Missing assembly identity and equal TypeRef
|
||||
names leave the comparison unknown.
|
||||
|
||||
Tokens are always remapped through observed structure. A caller cannot carry
|
||||
`0x06001234` into a new MVID and assume it names the same method.
|
||||
|
||||
@@ -374,7 +481,20 @@ point identities with supplied native export or function evidence. Name/module
|
||||
matches establish declaration links; they do not establish that a call executed.
|
||||
When either side lacks a usable module identity, a matching name remains
|
||||
unresolved and retains the candidate evidence; REA reports a module mismatch
|
||||
only when both identities are available and differ.
|
||||
only when both identities are available and their format-specific comparison
|
||||
establishes a difference. ELF module names retain case, PE module names compare
|
||||
case-insensitively, and a case-only match for Mach-O or an unknown format stays
|
||||
unresolved because the available Evidence does not establish case behavior.
|
||||
For PE imports, `.dll`, `.exe`, a trailing period, and absolute paths suppress
|
||||
appending `.dll`; other names may also be tried with `.dll`. Unix loaders use
|
||||
the platform suffix (`.so` or `.dylib`) and `lib` prefix variations. A suffix
|
||||
already present at the end of the name or before a period still gets an
|
||||
appended-suffix variation, so Linux can match `nativedep.so.6` with
|
||||
`libnativedep.so.6`. The `lib` prefix is omitted when the name contains `/`, and
|
||||
absolute paths are used as supplied. POSIX paths keep backslashes as literal
|
||||
characters. These candidates follow [Microsoft's native library loading rules](https://learn.microsoft.com/en-us/dotnet/standard/native-interop/native-library-loading).
|
||||
These filename rules compare declared and observed identities; they do not
|
||||
establish which library the runtime loaded.
|
||||
|
||||
Metadata tokens are not native addresses. Native body mapping for C++/CLI,
|
||||
ReadyToRun, NativeAOT, and IL2CPP requires separately verified format and provider
|
||||
@@ -385,6 +505,32 @@ Declared import inventory supports a bounded positive claim. Its absence does
|
||||
not exclude dynamic resolution, generated code, protected code, native helpers,
|
||||
or server-side behavior.
|
||||
|
||||
## Application graph relations
|
||||
|
||||
`project_managed_application_graph` turns member Evidence into `contains`
|
||||
edges for declarations, `imports` edges for P/Invoke declarations, and two
|
||||
relation kinds read from method bodies:
|
||||
|
||||
- `calls` links two `managed-method` nodes when a `call`, `callvirt`, `newobj`
|
||||
or `jmp` site in the caller targets a MethodDef in the inspected module.
|
||||
- `accesses` links a `managed-method` node to a `managed-field` node for each
|
||||
field it loads, stores or takes the address of.
|
||||
|
||||
Each edge stands for every site between one source and one target. Its
|
||||
properties carry `site_count` and per-opcode `opcodes` counts; `accesses`
|
||||
edges also list `access` as `read`, `write` and/or `address`. Edge evidence
|
||||
links the member Evidence.
|
||||
|
||||
Some sites are counted rather than projected: calls to MemberRefs (members of
|
||||
other assemblies or of generic type instantiations), generic method
|
||||
instantiations (`MethodSpec`), unknown targets, `ldftn`/`ldvirtftn` function
|
||||
pointer loads, recursive self-calls (the graph has no self-loops), MemberRef
|
||||
fields, and sites whose method or field node is absent, for example under a
|
||||
type selection. Limitations name each counted class, and graph coverage is
|
||||
`partial` with `omitted_count` equal to the omitted sites when nothing else is
|
||||
incomplete. A missing `calls` edge is therefore not evidence that a method is
|
||||
never called.
|
||||
|
||||
## Evidence record shape
|
||||
|
||||
Member comparison, application graph projection, and managed/native verification
|
||||
@@ -418,6 +564,10 @@ preserving readable member and attribute facts.
|
||||
The retained inverse indexes are admitted against the existing representation
|
||||
budget before allocation.
|
||||
|
||||
Custom-attribute `type_name` uses `Outer+Nested` when its local TypeDef or
|
||||
TypeRef enclosing chain is readable. It remains `null` when the constructor's
|
||||
type or required enclosing facts cannot be resolved.
|
||||
|
||||
`exported_types` reports ExportedType rows as declared. Facade assemblies such
|
||||
as .NET `System.Runtime.dll` provide their types this way: `forwarder: true`
|
||||
marks a type forwarder, and `implementation_token` names the AssemblyRef, File,
|
||||
@@ -431,6 +581,19 @@ CLI `#GUID` heap values retain their exact 16-byte GUID text. REA does not impos
|
||||
RFC 4122 UUID version or variant bits on MVID, EncId, or EncBaseId because
|
||||
ECMA-335 metadata does not require those bit patterns. Tokens and RVAs are
|
||||
build-local coordinates, not durable cross-build identities or native addresses.
|
||||
Field and method signatures validate embedded TypeDefOrRefOrSpec operands
|
||||
against the artifact's metadata tables. An invalid operand leaves the member
|
||||
name and raw signature digest available while marking that signature malformed
|
||||
and coverage partial.
|
||||
A fat method header's nonzero LocalVarSigTok must name an existing StandAloneSig
|
||||
row whose blob is a structurally valid LocalVarSig. REA validates its local
|
||||
types and exact blob coverage but does not project their identities. An invalid
|
||||
token or malformed signature leaves decoded CIL anchors intact but marks the
|
||||
body malformed and coverage partial. Unsupported local type encodings retain
|
||||
the readable body with partial coverage. Zero continues to mean no locals
|
||||
signature. Comparison detects whether a locals declaration is present, but raw
|
||||
table tokens are not cross-build identities and local type contents are not
|
||||
compared.
|
||||
|
||||
## Decoded-CIL fingerprint
|
||||
|
||||
@@ -456,6 +619,10 @@ Tuple operands use these exact projections:
|
||||
- signed integer and variable operands: decimal strings; floating-point
|
||||
operands: JavaScript's `String` representation of the decoded IEEE value.
|
||||
|
||||
For `ldtoken` MemberRef operands, `operand_kind` follows the parsed member
|
||||
signature (`field` or `method`); if that signature does not establish the kind,
|
||||
the anchor keeps the generic `token` classification.
|
||||
|
||||
Opcode names retain short/long forms and prefix opcodes. This makes the value a
|
||||
reproducible decoded-tuple fingerprint, not a canonical semantic CIL identity:
|
||||
it does not resolve tokens across MVIDs, does not commit full control flow or
|
||||
@@ -463,7 +630,8 @@ exception semantics, and does not replace the raw CIL digest. Cross-build
|
||||
comparison requires equal raw CIL digests as well for exact CIL/signature
|
||||
matches and reports ambiguity when structural evidence is insufficient.
|
||||
|
||||
For example, a decoded `nop; ret` body serializes exactly as
|
||||
For example, a present body (including any valid declared locals signature)
|
||||
whose IL is `nop; ret` serializes exactly as
|
||||
`[["nop","none",null],["ret","none",null]]` and has digest
|
||||
`5e5fad7741cb44bca3a4f045546b7449990da343f612f5f34c0ca30e9eee0636`.
|
||||
This vector specifies the tuple order, `null` handling, absence of whitespace,
|
||||
@@ -622,6 +790,13 @@ which managed methods executed or how the CLR resolved them.
|
||||
|
||||
Managed member comparisons report a `metadata` dimension when an observed
|
||||
MethodDef flags or implementation flags value differs, including accessibility
|
||||
or synchronization changes. This is separate from the CIL/signature matching
|
||||
tiers: identical instructions do not establish unchanged method metadata. The
|
||||
reported difference is static metadata evidence, not proof of runtime behavior.
|
||||
or synchronization changes. Observed method-body `init_locals` and `max_stack`
|
||||
differences also contribute to `metadata`, even when CIL decoding is incomplete.
|
||||
For complete bodies, presence or absence of a locals signature also contributes;
|
||||
the locals table token is build-local and is not compared. Local type contents
|
||||
are not currently compared, so this facet does not establish equivalent locals
|
||||
declarations.
|
||||
An unavailable header value keeps body coverage unknown rather than establishing
|
||||
equality or a difference. These comparisons are separate from the CIL/signature
|
||||
matching tiers: identical instructions do not establish unchanged method metadata.
|
||||
The reported difference is static metadata evidence, not proof of runtime behavior.
|
||||
+84
-22
@@ -44,12 +44,18 @@ root deltas. Missing graph members yield `truncated`; unknown traversal coverage
|
||||
or unavailable occurrence hashes retain uncertainty. Integrity mismatches remain
|
||||
contradictions. Static artifact equality does not establish unchanged runtime
|
||||
behavior.
|
||||
Source-map relation deltas include the content identity of the mapped source,
|
||||
so an unchanged map file is reported when its target source bytes change.
|
||||
|
||||
Exhausted traversals with deliberately omitted filesystem entries retain
|
||||
`unknown` coverage and identify each omitted path/type in `limitations`; FIFO,
|
||||
socket and device entries are not opened. Case-distinct archive members remain
|
||||
separate observations. Their case-insensitive materialization diagnostic does
|
||||
not reduce traversal coverage when both spellings were read.
|
||||
PyInstaller inventory also preserves distinct table rows that share a logical
|
||||
path, including decoded children beneath a colliding file/directory path.
|
||||
Inventory coverage describes observed archive facts; extraction still refuses
|
||||
destinations where those paths cannot coexist.
|
||||
|
||||
Current inventory Evidence requires scoped `coverage` with a `complete` or
|
||||
`unknown` status. Consumers use this producer-owned fact and reject records
|
||||
@@ -80,6 +86,12 @@ can observe backend recovery; healthy dossiers keep their existing cache policy.
|
||||
`procedure_pseudo_code` still fails for that function. Hopper's unavailable reference-kind metadata and reported unresolved
|
||||
calls still prevent equality conclusions for those dimensions. Analysis profiles
|
||||
version these declarations so older snapshots are not reused as current results.
|
||||
For `strings_names`, a string marked with `decoding.available: false` keeps its
|
||||
provider display text in the source Evidence, but that text is not compared as
|
||||
decoded content. If no independently known string, name, or literal fact differs,
|
||||
the dimension remains `unknown` with the decoding reason. Known content and typed
|
||||
string-object differences can establish a change; missing typed metadata remains
|
||||
unknown, and `encoding_status` describes provenance rather than content.
|
||||
IDA declares the facets its selected adapter cannot provide; an empty
|
||||
unsupported array does not prove observed absence.
|
||||
Evidence and bundle imports reject unsupported fields in their envelopes,
|
||||
@@ -95,11 +107,15 @@ optional bounded `recovery` next step. `recovery.kind=inspect_input_contract`
|
||||
names the rejected operation: re-read that operation's advertised input schema
|
||||
(call `tools/list` if the catalog may be stale), correct the listed fields, and
|
||||
do not repeat the unchanged call. `recovery.kind=inspect_timeout_state` names
|
||||
the operation and the REA server/provider deadline; inspect partial Evidence
|
||||
and reported cleanup state, then follow producer-specific remediation or reduce
|
||||
supported work. Generic errors do not assume adjustable timeout controls. Raising
|
||||
only the MCP client's deadline cannot extend this budget. These hints never
|
||||
include the complete catalog or caller arguments.
|
||||
the operation and the REA server/provider deadline. Inspect partial Evidence
|
||||
and reported cleanup state, then follow the returned remediation. Change a
|
||||
request field or REA_* setting only when the returned remediation explicitly
|
||||
recommends that change. Restart REA when that text says the value is read at
|
||||
startup. A mention that a control does not raise the deadline is not a
|
||||
recommendation to change it. When it names no setting, reduce supported work;
|
||||
do not invent one. Raising only the MCP
|
||||
client's deadline cannot extend this budget. These hints never include the
|
||||
complete catalog or caller arguments.
|
||||
Failures omit `structuredContent`, since each advertised `outputSchema`
|
||||
describes successful results. Successful replies retain their schema-validated
|
||||
structured data and matching text projection. Oversized errors are retained
|
||||
@@ -234,11 +250,14 @@ The destination changes only when a complete export is atomically published.
|
||||
|
||||
Clients that explicitly configure a larger receive buffer can set the REA
|
||||
server's `REA_MCP_MAX_RESPONSE_BYTES` environment variable to the same byte
|
||||
count. This setting must be a safe decimal integer at least 10485760; REA
|
||||
reserves 1024 bytes for the envelope. Raising it restores complete inline
|
||||
delivery for responses that fit that buffer and Node's single-string limit.
|
||||
It does not change the client's buffer, analysis coverage, or retained content.
|
||||
Ordinary responses keep their existing complete result contract.
|
||||
count. This setting must be a safe decimal integer at least 10485760 (10 MiB);
|
||||
REA reserves 1024 bytes for the envelope. The value is read when the REA
|
||||
process starts, so a change requires a restart and a matching client receive
|
||||
buffer. Raising it restores complete inline delivery for responses that fit
|
||||
that buffer. It does not raise REA's reserved single-string limit, which is
|
||||
1024 UTF-16 code units below Node's single-string ceiling, and it does not
|
||||
raise that Node ceiling. It does not change analysis coverage or retained
|
||||
content. Ordinary responses keep their existing complete result contract.
|
||||
|
||||
### Error recovery and deadline ownership
|
||||
|
||||
@@ -307,7 +326,9 @@ that complete Evidence in the session and returns the derived
|
||||
`normalized_result.parent_evidence_id` and `evidence_links` name the retained
|
||||
analysis, so later views and application workflows read it without repeating
|
||||
analysis or moving the complete record through the response. A server without
|
||||
session retention refuses summary detail with `capability_unavailable`.
|
||||
session retention refuses summary detail with `capability_unavailable`;
|
||||
`inspect_artifact`, `inspect_wasm_artifact`, `inspect_macho` and
|
||||
`decode_interface_builder` refuse before any analysis starts.
|
||||
For `inspect_artifact`, omission also keeps the original request parameters and
|
||||
complete output shape. Delivery selection never reaches the inventory engine;
|
||||
the complete inspection and its atomic inventory Evidence remain retained.
|
||||
@@ -329,7 +350,7 @@ See [environment manifests](web-network-captures.md#environment-manifest).
|
||||
|
||||
`inspect_analysis_view` also accepts `environment-state` for the same parents,
|
||||
extracting the initial state the recorded reads observed: entity types with an
|
||||
identity field, entities, documents for written non-entity paths, and a render
|
||||
identity field, entities, documents for non-entity reads, and a render
|
||||
plan per read tool that reproduces its recordings from the state or names why it
|
||||
cannot. Types and identity are inferences, so the Evidence is always inferred.
|
||||
See [environment state](web-network-captures.md#environment-state).
|
||||
@@ -988,6 +1009,16 @@ bytes and returns the `integrity_contradictions` records for the extracted
|
||||
files. An active ASAR unpacked entry whose companion file is absent cannot be
|
||||
materialized; extraction fails as `unavailable` with that logical path.
|
||||
|
||||
Extraction materializes regular files exposed by the active archive reader.
|
||||
When that reader exposes a nested archive as a file, extraction copies the
|
||||
archive file; inspect and extract that file separately to unpack its contents.
|
||||
Extraction retains inventory and materialization traversal limitations in its
|
||||
result and outer Evidence. If either traversal has unknown coverage, the
|
||||
observed regular files can still be copied, but the result does not establish
|
||||
a complete source copy. For example, a POSIX filename that is not valid UTF-8
|
||||
remains omitted with its raw-name explanation; it is not replacement-decoded
|
||||
into an output filename.
|
||||
|
||||
Packaging tools commonly sign or strip `.asar.unpacked` native binaries after
|
||||
writing the archive header, so their declared hashes no longer match. Electron
|
||||
does not check unpacked companions against those hashes at runtime. Integrity
|
||||
@@ -1139,20 +1170,43 @@ includes all dimension limitations. Equal CFGs establish only equal observed
|
||||
block sizes and successor relationships. Text from different provider
|
||||
identities remains unknown.
|
||||
|
||||
The `references` dimension preserves each edge's direction, endpoint identity
|
||||
and available kind facts. Within one artifact it compares exact raw endpoint
|
||||
coordinates, including the address space; hexadecimal case and zero padding
|
||||
do not change identity. Resolving an endpoint to a containing procedure does
|
||||
not replace the raw coordinate. Unparseable coordinates stay unknown.
|
||||
The `calls` and `references` dimensions share endpoint identity and name
|
||||
ambiguity rules. Calls retain procedure entry coordinates and direction;
|
||||
references retain each edge's raw source and target coordinates, direction and
|
||||
available kind facts. Resolving a reference endpoint to a containing procedure
|
||||
does not replace its raw coordinate. Hexadecimal case and zero padding do not
|
||||
change coordinates; address spaces remain distinct.
|
||||
|
||||
Coordinate equality requires equal artifact digests and formats, a known equal
|
||||
architecture, and matching provider-owned native coordinate commitments. Those
|
||||
commitments retain the exact selected Mach-O image where available and a digest
|
||||
of the loader's mapping inputs. They exclude unrelated analysis settings, so
|
||||
changing an analyzer option alone does not invalidate coordinate correspondence.
|
||||
Equal coordinates in different slices or mappings cannot establish equality.
|
||||
Hopper's default executable profile and Ghidra's supported deterministic imports
|
||||
publish these commitments. Hopper loader overrides and attached databases, IDA
|
||||
profiles, Ghidra universal-image imports without an exact slice commitment, and
|
||||
older or imported Evidence without a commitment leave coordinate identity
|
||||
unknown. Unparseable coordinates also remain unknown.
|
||||
|
||||
Across different artifacts, endpoints use nonempty stable procedure names.
|
||||
Missing or address-generated names remain unknown. A name observed at multiple
|
||||
procedure entries across either dossier's call and reference facets retains its
|
||||
label constraint but cannot establish equal endpoints. Same-container records
|
||||
without a common coordinate context likewise cannot establish equality from
|
||||
matching labels. Procedure labels do not carry authoritative symbol-origin
|
||||
facts, so recognition of generated names remains conservative and cannot prove
|
||||
whether every provider label was generated or explicitly named.
|
||||
|
||||
Across artifacts, reference endpoints use stable procedure names. Missing or
|
||||
address-generated names remain unknown. A name observed at multiple procedure
|
||||
entries retains its label constraint but cannot establish equal endpoints.
|
||||
Pairing preserves duplicate counts and considers alternative compatible
|
||||
pairings; array order never identifies an edge. Compatible records with
|
||||
unknown endpoint identity or kind facts remain `unknown`. Independent known
|
||||
pairings; array order never identifies an edge. Compatible records with unknown
|
||||
endpoint identity or reference kind facts remain `unknown`. Independent known
|
||||
facts that contradict every possible pairing still establish `changed`.
|
||||
Source Evidence retains the original addresses, names and unavailable facts.
|
||||
Reconstruction verification uses the selected dimension's status: a same-name
|
||||
call retargeting in a common context fails a calls claim; an unresolved slice or
|
||||
mapping cannot pass it. Empty function labels leave `function_match` ambiguous
|
||||
and the identity dimension unknown.
|
||||
|
||||
### Comparison input shapes
|
||||
|
||||
@@ -1173,6 +1227,14 @@ invoking the handler. Domain validation additionally checks
|
||||
relationships such as event sequence references and retained counts; JSON
|
||||
Schema does not express those cross-field invariants.
|
||||
|
||||
Comparison also preserves the capture's coverage. A partial HTTP inventory can
|
||||
establish an observed difference against a complete peer, but an omitted request
|
||||
does not establish removal. Partial WebSocket streams do not establish frame
|
||||
alignment. WebMCP frame IDs and tool keys are local to a capture; semantic owner
|
||||
facts and known counts determine correspondence. Retained script digests can
|
||||
establish source changes. See [browser comparison semantics](browser-observation.md)
|
||||
for value uncertainty and storage-fingerprint recapture requirements.
|
||||
|
||||
## Generated catalog
|
||||
|
||||
Custom clients upgrading from 6.1 should follow the
|
||||
|
||||
+123
-5
@@ -30,6 +30,11 @@ result records the exact selected path, file size, header length, header SHA-256
|
||||
bytes read and read scope. GGUF alignment padding is outside this prefix.
|
||||
`artifact.sha256` and the Evidence subject are null: a header digest is not a
|
||||
commitment to the weights. Different files can have identical headers and sizes.
|
||||
The reported GGUF tensor-data offset follows the aligned tensor directory when
|
||||
padding is present. For zero-tensor metadata-only files that end at the
|
||||
directory, it is the directory end; no tensor payload is implied. A partial
|
||||
alignment gap is rejected. `header_length` still ends at the directory, before
|
||||
any padding.
|
||||
|
||||
`hash: "full"` additionally streams the remaining file bytes through SHA-256.
|
||||
It returns a full-file digest and Evidence subject, while retaining the same
|
||||
@@ -39,13 +44,34 @@ check descriptor and selected-path identity and metadata before completion;
|
||||
this detects observed replacement or modification, not adversarial modification
|
||||
that defeats filesystem metadata checks.
|
||||
|
||||
If full-file hashing fails or is cancelled after either format's header has
|
||||
been validated, partial Evidence retains the parsed metadata and tensor directory.
|
||||
Header coverage is complete; digests and final file identity remain unknown.
|
||||
Safetensors header parsing is atomic, so interruption before validation does not
|
||||
expose unvalidated JSON rows.
|
||||
|
||||
## Facts and selected queries
|
||||
|
||||
GGUF reports version, byte order, alignment, typed metadata, and each tensor's
|
||||
name, original type ID, dimensions, relative data offset, file offset and derived
|
||||
byte length. Alignment accepts every positive UINT32 multiple of eight, including
|
||||
non-powers of two. Metadata keys use ASCII lower-snake-case hierarchy components;
|
||||
non-powers of two. Partial Evidence retains explicit alignment once validated;
|
||||
the default alignment becomes known after metadata completes. Cancellation
|
||||
retains completed declarations with unknown digests and unverified final file
|
||||
identity. Metadata keys preserve their spelling and use lowercase
|
||||
ASCII alphanumeric components separated by dots, underscores or hyphens;
|
||||
standard numeric components such as `general.base_model.0.name` are preserved.
|
||||
Hyphenated components are retained for compatibility with the published
|
||||
llama.cpp v0.7.0 writer, which emits keys such as
|
||||
`gpt-oss.context_length` and `wavtokenizer-dec.context_length`; the current
|
||||
[GGUF specification](https://github.com/ggml-org/ggml/blob/master/docs/gguf.md#standardized-key-value-pairs)
|
||||
restricts `general.architecture` values to letters and digits.
|
||||
This documents producer output that conflicts with that written restriction,
|
||||
not a claim that the specification permits hyphens. See the pinned
|
||||
[WAVTOKENIZER_DEC](https://github.com/ggml-org/llama.cpp/blob/620d2225cc436ab0b001e3200e590e3b286ef9ab/gguf-py/gguf/constants.py#L1447)
|
||||
and [GPT_OSS](https://github.com/ggml-org/llama.cpp/blob/620d2225cc436ab0b001e3200e590e3b286ef9ab/gguf-py/gguf/constants.py#L1466)
|
||||
architecture names, [context-length key template](https://github.com/ggml-org/llama.cpp/blob/620d2225cc436ab0b001e3200e590e3b286ef9ab/gguf-py/gguf/constants.py#L110),
|
||||
and [writer method](https://github.com/ggml-org/llama.cpp/blob/620d2225cc436ab0b001e3200e590e3b286ef9ab/gguf-py/gguf/gguf_writer.py#L698-L699).
|
||||
Scalar metadata is complete. Arrays have declared element types,
|
||||
counts and at most eight preview elements per array, with an explicit
|
||||
`preview_complete` flag. This includes tokenizer vocabularies: omitted values
|
||||
@@ -55,11 +81,101 @@ Nonfinite floating metadata uses `NaN`, `+Infinity` or `-Infinity` with its
|
||||
declared float type; negative zero is `"-0"`. Unknown tensor types retain their numeric IDs and null byte
|
||||
lengths; affected totals and storage validation remain unknown.
|
||||
|
||||
Q8_1 (type ID 9) has two released layouts: 40 bytes per 32 elements in
|
||||
[llama.cpp b1500](https://github.com/ggml-org/llama.cpp/blob/57ad015dc3011b046ed5a23186c86ea55f987c54/ggml-quants.h#L49-L55)
|
||||
and 36 bytes in the pinned
|
||||
[modern ggml layout](https://github.com/ggml-org/ggml/blob/da8e2a54b919557b816b1c2beb432ccb766f7ce0/src/ggml-common.h#L242-L253). Both use GGUF v3 and
|
||||
quantization version 2, so those declarations do not select a storage layout.
|
||||
REA retains the known type, shape, parameter count and starting offsets, with
|
||||
`byte_length: null`, `storage_validation: "unknown"`, partial storage/range
|
||||
coverage and an explicit limitation for nonempty Q8_1 tensors. Per-type and
|
||||
overall byte totals remain unknown where affected. Padding, the next tensor's
|
||||
offset and file size do not establish a layout; retained queries preserve the
|
||||
same uncertainty. Empty Q8_1 tensors still have a derived zero-byte length,
|
||||
and the known 32-element row-block constraint remains enforced.
|
||||
|
||||
K-quantization IDs 10–15 also have incompatible released layouts. The
|
||||
[b1500 build option](https://github.com/ggml-org/llama.cpp/blob/57ad015dc3011b046ed5a23186c86ea55f987c54/CMakeLists.txt#L88)
|
||||
`LLAMA_QKK_64` selects `GGML_QKK_64`; the same release's default and
|
||||
[b3001](https://github.com/ggml-org/llama.cpp/blob/c429b33beb35f13934a4dfbe0c138d30b45e5d54/ggml-common.h)
|
||||
use 256-element blocks. The
|
||||
[b1500 structures](https://github.com/ggml-org/llama.cpp/blob/57ad015dc3011b046ed5a23186c86ea55f987c54/ggml-quants.h#L61-L169)
|
||||
give these source-derived sizes:
|
||||
|
||||
| ID | Stable name | Bytes per 64 elements, K64 | Bytes per 256 elements, K256 | Padded extent for 256 elements, either layout |
|
||||
| --- | ----------- | -------------------------- | ---------------------------- | --------------------------------------------- |
|
||||
| 10 | Q2_K | 24 | 84 | 96 |
|
||||
| 11 | Q3_K | 28 | 110 | 128 |
|
||||
| 12 | Q4_K | 38 | 144 | 160 |
|
||||
| 13 | Q5_K | 46 | 176 | 192 |
|
||||
| 14 | Q6_K | 54 | 210 | 224 |
|
||||
| 15 | Q8_K | 76 | 292 | 320 |
|
||||
|
||||
Both builds write GGUF v3 and quantization version 2. The
|
||||
[quantizer](https://github.com/ggml-org/llama.cpp/blob/57ad015dc3011b046ed5a23186c86ea55f987c54/llama.cpp#L7430-L7492)
|
||||
writes `general.file_type` directly from the selected `llama_ftype`, without
|
||||
encoding the K64 build option. `GGML_QNT_VERSION_FACTOR` is defined in the
|
||||
header but is not used by this GGUF serialization path. Global file type also
|
||||
does not identify individual tensor types: the quantizer
|
||||
[retains unselected tensors](https://github.com/ggml-org/llama.cpp/blob/57ad015dc3011b046ed5a23186c86ea55f987c54/llama.cpp#L7561-L7586).
|
||||
The [writer pads each payload](https://github.com/ggml-org/llama.cpp/blob/57ad015dc3011b046ed5a23186c86ea55f987c54/ggml.c#L19549-L19565)
|
||||
to the default 32-byte alignment; the final column shows why even the same file
|
||||
extents need not distinguish these layouts.
|
||||
REA preserves each K type's name and enforces the common 64-element row
|
||||
multiple, which does not establish a storage block size. Nonempty K tensor
|
||||
lengths and affected totals are now unknown, including common modern files.
|
||||
Empty K tensors still have derived zero-byte storage.
|
||||
|
||||
Integer IDs also shifted each time IQ types were added. These released
|
||||
`ggml.h` snapshots all declare GGUF v3 and quantization version 2:
|
||||
|
||||
| Released snapshot | I8 ID | I16 ID | I32 ID |
|
||||
| --------------------------------------------------------------------------------------------------- | ----- | ------ | ------ |
|
||||
| [b1500](https://github.com/ggml-org/llama.cpp/blob/57ad015dc3011b046ed5a23186c86ea55f987c54/ggml.h) | 16 | 17 | 18 |
|
||||
| [b1803](https://github.com/ggml-org/llama.cpp/blob/36e5a08b203542dca53cca4eaf172c5dc4bbc991/ggml.h) | 17 | 18 | 19 |
|
||||
| [b1871](https://github.com/ggml-org/llama.cpp/blob/bb0c1392479398f9aba86d9ec98db0b95ede6e6d/ggml.h) | 18 | 19 | 20 |
|
||||
| [b2100](https://github.com/ggml-org/llama.cpp/blob/4aa43fab569215a13495a7f1a0f8afc541b16d03/ggml.h) | 19 | 20 | 21 |
|
||||
| [b2172](https://github.com/ggml-org/llama.cpp/blob/bd2d4e393b2b7d2a1b2e201058e26017c9728ead/ggml.h) | 20 | 21 | 22 |
|
||||
| [b2221](https://github.com/ggml-org/llama.cpp/blob/a14679cc30c785e75d38028bae6ec39c6209ddef/ggml.h) | 21 | 22 | 23 |
|
||||
| [b2253](https://github.com/ggml-org/llama.cpp/blob/4c4cb30736582cacb1a164a9d4bc8e17b1014be7/ggml.h) | 22 | 23 | 24 |
|
||||
| [b2275](https://github.com/ggml-org/llama.cpp/blob/a33e6a0d2a66104ea9a906bdbf8a94d050189d91/ggml.h) | 23 | 24 | 25 |
|
||||
| [b2300](https://github.com/ggml-org/llama.cpp/blob/6ea0f010ff6967034528d9e0b8330b9b0f0b7c13/ggml.h) | 24 | 25 | 26 |
|
||||
|
||||
[Upstream PR 6050](https://github.com/ggml-org/llama.cpp/pull/6050) later pinned
|
||||
integer values explicitly. Modern IDs 16–23 mean IQ2_XXS, IQ2_XS, IQ3_XXS,
|
||||
IQ1_S, IQ4_NL, IQ3_S, IQ2_S and IQ4_XS, respectively. Thus every ID 16–25 has
|
||||
multiple released meanings. REA keeps its numeric `type_id`, uses
|
||||
`AMBIGUOUS_<id>` for `type`, and records the released candidate names in a
|
||||
limitation. Nonempty byte lengths are unknown. Empty declarations still derive
|
||||
zero-byte storage, while their textual identity remains ambiguous. Type filters
|
||||
match the reported `AMBIGUOUS_<id>` label. ID 26 remains I32 across these
|
||||
snapshots; later stable entries retain their existing interpretation. This audit
|
||||
does not establish compatibility with every producer fork or future revision.
|
||||
|
||||
The inventory does not select a historical layout from model names, global
|
||||
file types, padding or guessed producer provenance. A source revision together
|
||||
with its build configuration can establish an external layout fact; these
|
||||
headers do not carry that identification, and REA currently has no layout
|
||||
selection input. Authored regression fixtures use the source-derived sizes
|
||||
above; historical executables were not run.
|
||||
|
||||
Safetensors reports the header extent, exact string `__metadata__` values, dtype,
|
||||
shape and declared data ranges. JSON duplicate keys, invalid UTF-8, out-of-file
|
||||
shape and declared data ranges. A null `__metadata__` is treated as omitted;
|
||||
unknown fields on tensor entries are ignored within the reader's 32-level JSON
|
||||
nesting limit, while the required dtype, shape and data offsets are still
|
||||
validated. JSON duplicate keys, invalid UTF-8, out-of-file
|
||||
ranges, overlaps, gaps, trailing unindexed data and known dtype/shape byte-length
|
||||
contradictions are rejected with a typed `file_format_rejected` constraint (public code `target_unavailable`, category `unsupported_target`). Empty
|
||||
tensors and scalar shapes are supported; packed sub-byte types require whole
|
||||
contradictions are rejected with a typed `file_format_rejected` constraint (public code `target_unavailable`, category `unsupported_target`).
|
||||
A missing, non-regular or otherwise unusable selected path is also `target_unavailable`;
|
||||
host I/O or resource failures on a valid selection, such as `EMFILE` or `EIO`, are
|
||||
`execution_failure` with the path and reason in `details.diagnostics`. Empty
|
||||
tensors and scalar shapes are supported. The reader retains shape dimensions as
|
||||
exact unsigned 64-bit values, including values above JavaScript's safe-integer
|
||||
range when a zero extent makes storage empty. Shape products are checked in
|
||||
declaration order, as in the
|
||||
[64-bit upstream reader](https://github.com/huggingface/safetensors/blob/e246a2560645b7525f5775669ed816eb57c5bcc8/safetensors/src/tensor.rs#L604-L609);
|
||||
a later zero does not erase an earlier product overflow. Actual file and data
|
||||
offsets must still fit exact host offset precision. Packed sub-byte types require whole
|
||||
byte storage. Unknown dtypes retain declared ranges and an explicit limitation
|
||||
that shape-to-storage validation is unavailable. Each tensor records
|
||||
`storage_validation: "consistent" | "unknown"`; `coverage.storage_sizes` remains
|
||||
@@ -76,7 +192,9 @@ GGUF supports zero extents and scalar shapes, with at most four dimensions;
|
||||
known quantized types still require complete blocks in the first dimension.
|
||||
|
||||
MCP defaults to a compact summary with counts, selected short headline metadata,
|
||||
chat-template presence and derived totals. The full type histogram and all rows
|
||||
chat-template presence (default or named template content) and derived totals.
|
||||
A names-only `tokenizer.chat_templates` inventory does not establish template
|
||||
content. The full type histogram and all rows
|
||||
remain in complete Evidence. Headline metadata uses short keys/types and scalar
|
||||
values; long or compound values remain available through explicit metadata
|
||||
queries. Use the returned `parent_evidence_id`:
|
||||
|
||||
+158
-10
@@ -6,6 +6,15 @@ Use a native provider to discover functions, inspect instructions and pseudocode
|
||||
follow references, and examine database types. Static resources and runtime
|
||||
observation complement that analysis when they answer a specific question.
|
||||
|
||||
`inspect_macho` reports build platforms from the selected slice. Legacy
|
||||
`LC_VERSION_MIN_IPHONEOS`, `LC_VERSION_MIN_TVOS` and
|
||||
`LC_VERSION_MIN_WATCHOS` commands are interpreted with the Mach-O CPU type, so
|
||||
Intel slices report simulator platforms while device CPU slices keep the
|
||||
device platform. A chained-import row ending in `+0x...` is ambiguous in
|
||||
dyld's text output: it may be an addend or part of a literal symbol name. REA
|
||||
keeps the full expression in `raw_name`, sets `name` and `addend` to null, and
|
||||
marks `name_status: "ambiguous"`; it does not synthesize a symbol identity.
|
||||
|
||||
## Start with a function
|
||||
|
||||
Choose an installed provider from [setup](installation.md#hopper). For Ghidra:
|
||||
@@ -202,10 +211,52 @@ Function dossiers retain this same string evidence. Native call edges retain
|
||||
Hopper's partial `CallReference` classification and exact endpoints; detailed
|
||||
reference flags remain unavailable rather than being invented.
|
||||
Regex searches use ECMAScript Unicode syntax in a cancellable worker with a
|
||||
five-second matching deadline and a 128 MiB worker heap. Deadline or
|
||||
cancellation stops matching while leaving the Hopper API available. This
|
||||
release has no runtime override for that deadline or heap. Literal mode
|
||||
retains Unicode casefold matching.
|
||||
matching deadline and a worker old-generation heap. Deadline or cancellation
|
||||
stops matching while leaving the Hopper API available. The deadline is
|
||||
`REA_REGEX_MATCHING_DEADLINE_MS`, a positive decimal integer from 1 to
|
||||
2147483647 ms. Unset uses 5000 ms. A larger value is refused because Node
|
||||
schedules a delay past that signed 32-bit bound as 1 ms. Invalid values are
|
||||
configuration errors and do not fall back to the default. The setting is read
|
||||
from the environment that starts REA, so a change needs a restart. A deadline
|
||||
failure names the effective milliseconds, whether they came from the default
|
||||
or the setting, the default, and the maximum. The worker old-generation heap
|
||||
does not raise it. Kuna regex search uses the same deadline. The worker
|
||||
heap request is `REA_REGEX_WORKER_HEAP_REQUEST_MIB`, a decimal integer from
|
||||
7 to 16384 MiB. Unset uses 128 MiB. A request below 7 MiB aborts the worker
|
||||
during startup, and a larger value is refused. Invalid values are
|
||||
configuration errors and do not fall back to 128. The setting is read from
|
||||
the environment that starts REA, so a change needs a restart. A heap failure
|
||||
names the effective request, whether it came from the default or the setting,
|
||||
the default, the floor, and the maximum. A positive Node.js
|
||||
`--max-old-space-size` on the process that starts
|
||||
REA, including `NODE_OPTIONS`, overrides that request and sets the effective
|
||||
heap. `--max-old-space-size-percentage` takes precedence over that flag in
|
||||
either order. REA does not turn the percentage into a MiB, so the effective
|
||||
heap stays unestablished instead of the worker heap request or the absolute flag.
|
||||
The reported `NODE_OPTIONS` value is the process initial environment when that
|
||||
block can be read. A later edit to the environment is not the value Node
|
||||
applied, and an unreadable initial value leaves the effective heap
|
||||
unestablished. The launch Node options are the initial command line on Linux
|
||||
when that buffer still has a program entry, not a later edit to
|
||||
`process.execArgv`. A preload can clear that array after V8 has applied the
|
||||
flags. Setting `process.title` or `--title` overwrites the command line, so a
|
||||
buffer without a program entry leaves the effective heap unestablished.
|
||||
`--env-file` or `--env-file-if-exists` can supply `NODE_OPTIONS`
|
||||
when the initial environment has none. That file is not part of the initial
|
||||
environment block, so the effective heap stays unestablished instead of the
|
||||
worker heap request. An initial `NODE_OPTIONS` is still used, because Node does
|
||||
not let the file replace it. A positive `--max-heap-size`, including the
|
||||
underscore form and launch `NODE_OPTIONS` on Node versions that allow it,
|
||||
sets the total heap rather than the old generation and can be lower than the
|
||||
worker heap request. The effective old generation stays unestablished while that
|
||||
value is in effect. A zero or empty value clears it.
|
||||
`--experimental-config-file` or `--experimental-default-config-file` can set
|
||||
`nodeOptions`, including a heap percentage, from a file that is not read
|
||||
back. The effective heap stays unestablished when either flag is present,
|
||||
including when an absolute `--max-old-space-size` is also on the command
|
||||
line or in the recovered `NODE_OPTIONS`. Node accepts the config path as
|
||||
`=` or the next argument.
|
||||
Literal mode retains Unicode casefold matching.
|
||||
|
||||
## Bounded static traces
|
||||
|
||||
@@ -293,6 +344,21 @@ Mach-O fixtures check each case against source-owned return values.
|
||||
|
||||
## Static inspection
|
||||
|
||||
`inspect_artifact` and `extract_artifact` retain universal Mach-O slices under
|
||||
their exact `lipo` names, including 32-bit ARM implementations such as `armv7`,
|
||||
`armv7s`, and `armv7k`. These names are reconciled with the FAT CPU subtype;
|
||||
the structural reader's `arm` family label alone does not identify a slice.
|
||||
Available CPU type, subtype/capability bits, byte range, and alignment remain
|
||||
checked against the source bytes. Inventory records source ranges and hashes, and
|
||||
extraction copies those ranges without running the target. This does not
|
||||
expand any analysis provider's supported architectures.
|
||||
Apple lipo's hidden ARM64 compatibility row is retained separately from the
|
||||
raw `nfat_arch` count and admitted only from its extra FAT table slot when its
|
||||
in-range Mach-O header matches the row. `list_architectures` preserves the
|
||||
per-row `hidden` marker from lipo output. Mach-O image and Electron fuse
|
||||
inspection include the row in architecture selection while retaining that
|
||||
marker in their reported slices.
|
||||
|
||||
`inspect_plist.format` describes the selected source, not plutil's conversion
|
||||
format. Sources explicitly identified as XML, binary or JSON retain those
|
||||
labels. For generic text, a bounded source-prefix probe recognizes leading XML
|
||||
@@ -367,9 +433,16 @@ complete observation.
|
||||
its outcome. Paths outside the analyzed root, including shared-cache system
|
||||
libraries, stay undetermined. See
|
||||
[Apple application analysis](apple-application-analysis.md#dylib-load-resolution).
|
||||
Executable-root discovery preserves traversal uncertainty, including
|
||||
undecodable filenames and skipped symlinks, as partial coverage. Known
|
||||
executable roots remain available; unexamined names and symlink targets
|
||||
cannot establish an empty root set or the absence of other roots.
|
||||
- `inspect_asset_catalog` / `rea inspect-asset-catalog <app>` reads compiled
|
||||
`Assets.car` metadata through macOS `assetutil --info`. Catalog digests, raw
|
||||
rendition fields, pagination and exact UI resource-name matches are returned.
|
||||
`inventory_coverage` describes traversal of source entries and remains
|
||||
`unknown` when the reader cannot represent a filename. Represented symlinks
|
||||
are inventoried but their targets remain uninspected, with a limitation.
|
||||
Image extraction and undocumented rendition interpretation are unsupported.
|
||||
- `inspect_keyed_archive` / `rea inspect-keyed-archive <plist>` reads XML or
|
||||
binary Foundation keyed archives without instantiating classes. For an active
|
||||
@@ -387,6 +460,19 @@ complete observation.
|
||||
emits no bytes. Character references retain their source spelling for data
|
||||
decoding. Non-ASCII content, child markup and self-closing `<data/>` are format
|
||||
failures; explicit `<data></data>` represents empty data.
|
||||
Each XML dictionary key must have a following value element; a final key
|
||||
without one is malformed. An explicit empty string remains a value.
|
||||
Binary UID payloads may use nonminimal byte widths. REA normalizes them only
|
||||
in a private decoder copy; archive digests still identify the original bytes.
|
||||
Positive binary-plist offset and object-reference table widths are read from
|
||||
the source; nonstandard widths are normalized only in that private copy for
|
||||
the pinned decoder. [Foundation's table checks](https://github.com/swiftlang/swift-corelibs-foundation/blob/swift-6.2.3-RELEASE/Sources/CoreFoundation/CFBinaryPList.c#L759-L789)
|
||||
accept positive widths subject to extent/reference bounds, and its
|
||||
[sized-integer reader](https://github.com/swiftlang/swift-corelibs-foundation/blob/swift-6.2.3-RELEASE/Sources/CoreFoundation/CFBinaryPList.c#L707-L730)
|
||||
handles non-power sizes. Widths over eight bytes follow its unsigned 64-bit
|
||||
accumulator semantics.
|
||||
UID values above JavaScript's exact integer range return an unsupported-target
|
||||
outcome instead of rounded reference identities.
|
||||
UID 0 cannot distinguish conditional nil from ordinary nil. Limits are
|
||||
64 MiB of input, 200,000 objects/references and 128 nesting levels.
|
||||
XML dictionary entries decoded as `__proto__` are omitted with an explicit
|
||||
@@ -430,15 +516,44 @@ complete observation.
|
||||
Archives beyond either aggregate budget are omitted with their paths and an
|
||||
explicitly partial `archive_decode` facet; previously decoded documents and
|
||||
their identities remain available.
|
||||
The same facet is partial when source traversal cannot represent a filename
|
||||
or an archive-shaped symlink was skipped. Unknown filename coverage has no
|
||||
invented document count; known skipped nib and storyboard links are counted
|
||||
as omitted. A readable empty bundle can report complete zero-document
|
||||
coverage. Source I/O and identity failures retain their acquisition error
|
||||
instead of being labeled invalid archive content. Rejected plist decodes
|
||||
release their representation reservation for later documents.
|
||||
- `inspect_native_dispatch_metadata` /
|
||||
`rea inspect-native-dispatch-metadata <app-or-binary>` prefers a validated macOS Mach-O byte reader. It decodes
|
||||
64-bit little-endian Objective-C class/metaclass records, superclass pointers,
|
||||
absolute/relative method entries, ivar offsets/sizes/alignment and protocol
|
||||
declarations. It also decodes simple Swift conformances, static synchronous
|
||||
witness slots, signed-relative pointers and non-generic, non-resilient class
|
||||
vtable descriptors. Records include exact virtual addresses/file offsets and
|
||||
declarations. It also decodes Swift nominal type declarations, simple Swift
|
||||
conformances, static synchronous witness slots, signed-relative pointers and
|
||||
non-generic, non-resilient class vtable descriptors. Records include exact virtual addresses/file offsets and
|
||||
artifact evidence. Vtable indexes are metadata word offsets; witness indexes
|
||||
start after the conformance header. Names unavailable in metadata remain null.
|
||||
The byte reader holds the whole selected file in memory, so it admits files up
|
||||
to 64 MiB / 67108864 bytes by default. Select a larger budget with
|
||||
`max_input_bytes` (CLI `--max-input-bytes`), at most 1 GiB / 1073741824
|
||||
bytes. The whole file counts, including every slice of a universal Mach-O.
|
||||
Results record `input_admission` with the effective budget, its source
|
||||
(`default` or `caller`) and the bytes retained. A refusal names the observed
|
||||
file size, the effective budget and its source, and either the budget to
|
||||
select or, above 1 GiB, a deep analysis provider.
|
||||
`swift_decls` lists each `__swift5_types` nominal type descriptor, which
|
||||
survives stripping: `kind` (`class`, `struct`, `enum`, or `actor` from the
|
||||
class actor flag), the descriptor's own `name`, `module`, `qualified_name`
|
||||
(`Outer.Inner`), `generic`, the metadata `accessor_address`, the descriptor
|
||||
`location`, and evidence citing its `__swift5_types` record.
|
||||
Private and local types set `anonymous_context` because their anonymous
|
||||
context is omitted from `qualified_name`. When a parent context cannot be
|
||||
resolved, such as an extension of a type named only by a mangled name, a
|
||||
missing module, or a cyclic chain, `qualified_name` is null and the entry is
|
||||
partial with a reason. Access level, superclass, conformances, and fields are
|
||||
not reported by this facet. The `swift_declarations` coverage counters count
|
||||
examined type records and fully decoded declarations. Class vtable recovery
|
||||
reads the same descriptors, so an unreadable type record also keeps
|
||||
`swift_class_vtable_descriptors` partial.
|
||||
The `swift_class_vtable_descriptors` coverage counters count examined vtable
|
||||
slots and successfully decoded slots, rather than type-section entries.
|
||||
The `objc_class_method_ivar_metadata` counters count admitted class and
|
||||
@@ -469,7 +584,8 @@ complete observation.
|
||||
So an external superclass resolves from its `_OBJC_CLASS_$_` bind (for
|
||||
example `NSObject`). The `pointer_fixups` coverage facet names the mechanism.
|
||||
Class properties preserve each encoded attribute as a raw `{name, value}`
|
||||
pair, for example `{ name: "N", value: "" }`, and report atomicity on the
|
||||
pair, including commas inside C++ template arguments in the `T` type, for
|
||||
example `{ name: "N", value: "" }`, and report atomicity on the
|
||||
property: `N` means `nonatomic`; a complete typed attribute string without
|
||||
`N` means the Objective-C default `atomic`;
|
||||
missing or incomplete attribute metadata leaves `atomicity` and any
|
||||
@@ -678,6 +794,15 @@ unresolved runtime/value semantics remain visible in results.
|
||||
|
||||
## Interface Builder hierarchy coverage
|
||||
|
||||
Bundle archive selection preserves directory traversal uncertainty, including
|
||||
filenames that cannot be decoded as UTF-8. These names are not guessed or
|
||||
counted as known archive omissions. Recognized symlinked `.nib` entries are
|
||||
not followed; they retain their paths and reader limitations as counted archive
|
||||
omissions. Either gap makes `archive_decode` partial and the graph truncated
|
||||
while preserving decoded documents. Its `examined` count remains actual decode
|
||||
attempts, and asset-catalog UI joins retain their existing incomplete-graph
|
||||
qualification.
|
||||
|
||||
A document's `hierarchy_complete` flag follows its own hierarchy coverage.
|
||||
If graph limits omit a hierarchy source or destination, or prevent a hierarchy
|
||||
edge or traversal from being retained, that document reports partial hierarchy
|
||||
@@ -726,8 +851,31 @@ attributes; exact and ambiguous projection counts cover emitted attribute values
|
||||
Integral reals stay numbers, and ambiguous or incompletely observed values retain
|
||||
explicit precision limitations. Before plist decoding, the existing aggregate
|
||||
decode budget reserves estimated room for number metadata and attribute
|
||||
projection; these estimates are not a hard process-memory bound. Native
|
||||
NIBArchive decoding is unchanged by this plist-specific representation.
|
||||
projection; these estimates are not a hard process-memory bound. Keyed-archive
|
||||
object identities always come from their original `$objects` table indices.
|
||||
Authored `objectID`, `object-id`, `archiveUID` and `id` fields remain ordinary
|
||||
object data and do not change inventory, reference, connector or hierarchy
|
||||
identity. This changes keyed-archive graph IDs that previously used authored
|
||||
`objectID` or `object-id` values: `interface_builder_object_id` and linked node
|
||||
IDs now use the decimal table UID, while the authored values remain in attributes.
|
||||
For example, an authored `objectID: "2"` on table entry 1 now identifies object
|
||||
`"1"`; its graph node ends in `object:["1"]`. Nonkeyed ibtool dictionary IDs
|
||||
and native NIBArchive IDs keep their existing source-specific meaning.
|
||||
Connector endpoints require encoded UID references to archived objects; strings
|
||||
and dictionaries that merely resemble resolved reference stubs do not establish
|
||||
identity. Inline hierarchy dictionaries have no table identity and count as
|
||||
omitted references, while independently referenced children remain available.
|
||||
The UID identity rule follows the
|
||||
[Foundation unarchiver's table lookup](https://github.com/swiftlang/swift-corelibs-foundation/blob/28249ced079d8e7ec03b821c039bf9868738c3fc/Sources/Foundation/NSKeyedUnarchiver.swift#L213-L223).
|
||||
UIKit keyed nibs select their explicitly named
|
||||
`UINibTopLevelObjectsKey` collection; generic `root` is used when that named key
|
||||
is absent. Unsupported or dangling named roots remain incomplete rather than
|
||||
falling back to another collection. The key spelling follows the independent
|
||||
[WinObjC UINib reader](https://github.com/microsoft/WinObjC/blob/94f6b5bfdc09d945e30607b56124b6f94a5b9d7b/Frameworks/UIKit/UINib.mm#L104-L109).
|
||||
|
||||
NIBArchive float32 and float64 values retain non-finite values and negative zero
|
||||
through projection as the same typed real wrappers used for plist values; per-document limitations
|
||||
count those values. NIBArchive nil remains JSON null.
|
||||
|
||||
Dates are reported as `{ "$plist_type": "date", "iso8601": "<timestamp>" }`.
|
||||
XML dates require a complete UTC spelling with fixed two-digit month, day and
|
||||
|
||||
+11
-2
@@ -10,10 +10,17 @@ Supply an existing TShark 4.x installation **on Linux**, with util-linux
|
||||
`prlimit` available at `/usr/bin/prlimit`. Override its absolute path with
|
||||
`REA_TSHARK_PRLIMIT_COMMAND` if required. Unsupported hosts, including macOS
|
||||
and Windows, are refused before inspection because this integration requires
|
||||
an enforced address-space limit:
|
||||
an enforced address-space limit.
|
||||
|
||||
TShark selection follows the same rule as [`inspect_pcap_capture`](pcap-analysis.md):
|
||||
an absolute `REA_TSHARK_COMMAND`, otherwise `tshark` from the first absolute
|
||||
`PATH` entry that holds an executable file. A relative `REA_TSHARK_COMMAND` is
|
||||
refused rather than looked up. Either way the selected executable is resolved,
|
||||
hashed and rechecked after each run, and Evidence records its
|
||||
`selection_source` (`environment` or `path`):
|
||||
|
||||
```sh
|
||||
export REA_TSHARK_COMMAND=/absolute/path/to/tshark
|
||||
export REA_TSHARK_COMMAND=/absolute/path/to/tshark # optional when tshark is on PATH
|
||||
rea inspect-packet-capture /artifacts/device.pcapng \
|
||||
--fields ip.addr --fields udp.port --fields data.data \
|
||||
--display_filter 'udp' --format json
|
||||
@@ -88,6 +95,8 @@ for field names, display filters, decode-as syntax and pass semantics. Invalid
|
||||
fields or filters return producer diagnostics. An empty result does not prove
|
||||
absence of traffic outside the selected recording, filter or read range.
|
||||
Dissector results are observations, not independently verified device behavior.
|
||||
TShark may resolve a selected alias to its canonical field name in packet output;
|
||||
the report preserves the exact requested selection and the producer's output key.
|
||||
|
||||
Evidence includes source path/digest/size, exact selections, typed packet fields,
|
||||
configured and resolved executable paths/digests/full version banner, arguments and stderr. Warnings remain
|
||||
|
||||
+19
-4
@@ -17,7 +17,16 @@ rea inspect-pcap-capture /captures/session.pcapng --json
|
||||
```
|
||||
|
||||
Without explicit tool commands, this family resolves them through PATH and
|
||||
records that selection source. Client inspection reads no capture file. Capture
|
||||
records that selection source. On Linux and macOS it runs the tool found in the
|
||||
first absolute PATH entry holding an executable file, the same selection the
|
||||
[packet capture tools](packet-captures.md) make; relative PATH entries are
|
||||
skipped. Windows keeps PATH/PATHEXT resolution in the process launcher. Client
|
||||
inspection reads no capture file; on hosts where PATH/PATHEXT does not expose
|
||||
an absolute candidate, its executable digest and resolved path are reported as
|
||||
unresolved. Otherwise the canonical executable path and SHA-256 are reported.
|
||||
The pcap provider and packet tools share the selected-tool identity check, and
|
||||
changes to a resolved executable during a run fail with artifact-changed
|
||||
Evidence. Capture
|
||||
inspection requires Linux with util-linux prlimit or Windows with owned Job
|
||||
Objects. macOS capture inspection returns a capability gap because the new
|
||||
native memory boundary is unverified; its version probes remain available.
|
||||
@@ -77,6 +86,9 @@ not process identity or proof of the destination's authenticity.
|
||||
All examined inventories are retained within the resource budget; no fixed
|
||||
200/100/50-item truncation is applied. HTTP transport credentials are excluded
|
||||
without rewriting other URI bytes; ambiguous credential spans cause omission.
|
||||
The URI inventory includes absolute-form HTTP request targets when TShark cannot
|
||||
construct `http.request.full_uri` because no Host header was reported; relative
|
||||
request targets are not promoted to absolute URIs.
|
||||
Counts preserve distinct observed source URIs before omission or coalescing.
|
||||
`coverage: "partial"` records unresolved DNS attribution or URI item loss;
|
||||
component credential exclusion is also counted explicitly. Diagnostics retain
|
||||
@@ -100,9 +112,12 @@ wall deadlines are 300 s for dissection, 60 s for metadata and 20 s for probes.
|
||||
Native ownership preparation has its own bounded lifecycle.
|
||||
|
||||
Malformed/oversized output returns no partial success. Unvalidated partial JSON
|
||||
is not returned as facts. Cancellation reaches probes, acquisition, commands and
|
||||
projection. Cleanup failure returns a typed error, retains completed Evidence
|
||||
when available, and retains owned resources for retry on close.
|
||||
is not returned as facts. Invalid UTF-8 in either `capinfos` or TShark stdout or
|
||||
stderr is an unreadable-output error; replacement-decoded text is not parsed as
|
||||
producer evidence. A literal U+FFFD character in valid UTF-8 remains text.
|
||||
Cancellation reaches probes, acquisition, commands and projection. Cleanup
|
||||
failure returns a typed error, retains completed Evidence when available, and
|
||||
retains owned resources for retry on close.
|
||||
|
||||
## Verification scope
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# PE Authenticode certificate tables
|
||||
|
||||
`inspect_pe_certificates` / `inspect-pe-certificates` answers whether one
|
||||
selected local PE32/PE32+ image declares an `IMAGE_DIRECTORY_ENTRY_SECURITY`
|
||||
table, which `WIN_CERTIFICATE` entries that table stores, and which PKCS#7
|
||||
signer and X.509 fields those entries carry. It reads the file without
|
||||
executing it and does not require a Windows SDK, catalog file, or disassembler.
|
||||
|
||||
```bash
|
||||
rea inspect-pe-certificates /absolute/path/to/application.exe --json
|
||||
```
|
||||
|
||||
The CLI resolves relative paths against the caller's working directory. MCP
|
||||
and the advertised input schema require an absolute filesystem path and
|
||||
preserve that exact selection:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inspect_pe_certificates",
|
||||
"arguments": { "path": "/artifacts/application.exe" }
|
||||
}
|
||||
```
|
||||
|
||||
## Observations
|
||||
|
||||
The inline Evidence result contains the artifact path, SHA-256, and byte length.
|
||||
`table` is the file-offset security directory, or `null` when the directory is
|
||||
absent or zero. Each `entries[]` item reports `WIN_CERTIFICATE` length,
|
||||
revision, type, and the payload SHA-256.
|
||||
|
||||
For `WIN_CERTIFICATE` type 2 (PKCS#7 signedData) `pkcs7` contains digest
|
||||
algorithm OIDs, embedded X.509 serial/issuer/subject/validity fields, and
|
||||
signer identifier facts. A signer identified by subject key identifier reports
|
||||
that value as `subject_key_identifier_hex`. Other certificate types keep
|
||||
`pkcs7` null.
|
||||
|
||||
A missing table is observed absence of that directory. It is not proof the
|
||||
image is unsigned in every catalog or overlay sense.
|
||||
|
||||
## Limits and failures
|
||||
|
||||
The selected file is limited to 64 MiB by default (512 MiB maximum). At most
|
||||
eight `WIN_CERTIFICATE` entries are examined by default. Malformed PE headers,
|
||||
truncated certificate entries, and PKCS#7 that is not structurally signedData
|
||||
fail without partial success. A security directory that ends in fewer than
|
||||
eight header bytes, including zeros, is a truncated `WIN_CERTIFICATE` and
|
||||
fails the same way. SignedData must contain at least one `SignerInfo`, and
|
||||
each `SignerInfo` must carry a non-empty signature value. Each embedded X.509
|
||||
certificate must include `subjectPublicKeyInfo` and `signatureValue`. Decoded
|
||||
certificate name text, serials, validity spellings, and subject key identifiers
|
||||
share a 64 KiB budget per PKCS#7 payload. Unsupported certificate name
|
||||
encodings, including GeneralString, fail explicitly. TeletexString (T.61)
|
||||
values are rendered with the ISO-8859-1 compatibility mapping used by OpenSSL;
|
||||
this is not a full T.61 decoder, so the result includes a limitation whenever
|
||||
that mapping is used. RFC 5280 retains TeletexString for backward compatibility
|
||||
and describes its repertoire as ASCII-like Latin with additional characters.
|
||||
|
||||
The structural CMS reader accepts definite lengths and BER indefinite lengths
|
||||
for constructed values, including the outer `ContentInfo` sequence. Primitive
|
||||
values must have definite lengths. Embedded X.509 certificates and signed
|
||||
attributes must also use definite length encoding, as required by their DER
|
||||
profiles. This is a bounded structural subset: it does not implement every BER
|
||||
string form or validate DER canonical encoding, and it does not verify
|
||||
signatures.
|
||||
|
||||
This workflow does not verify signatures, certificate chains, timestamps, or
|
||||
Authenticode digest coverage of image bytes.
|
||||
+19
-1
@@ -252,7 +252,14 @@ Successfully observed identity replacements use `identity_changed` with a null
|
||||
system code. Unstable symlink targets are omitted; already observed directory
|
||||
metadata remains available. The affected root stays incomplete, so omitted
|
||||
entries do not prove deletion. A path missing at its initial lookup remains an
|
||||
observed absence. Cancellation and unexpected I/O failures still stop capture.
|
||||
observed absence.
|
||||
|
||||
Before launch, a selected root below a non-directory, or one whose lookup is
|
||||
denied or otherwise unavailable, fails capture. After admission, a root or descendant lookup that
|
||||
reports a missing path or a non-directory ancestor is an observed absence. A
|
||||
denied or otherwise unavailable lookup records an `entry_unavailable` omission
|
||||
for that path instead, and its root stays incomplete. Cancellation and
|
||||
unexpected I/O failures still stop capture.
|
||||
|
||||
Terminal frame `data` is the comparison text after the selected normalization.
|
||||
New captures also preserve `raw_data` when normalization changes a PTY chunk;
|
||||
@@ -262,6 +269,13 @@ while comparisons and trace assertions use the normalized text. Retaining the
|
||||
original adds at most `limits.output_bytes` of text, because it comes from the
|
||||
same admitted PTY chunks rather than a second unbounded stream.
|
||||
|
||||
When path normalization is enabled, aliases apply to selected path identities
|
||||
at clear text delimiters. A selected executable path does not alias a longer
|
||||
sibling filename such as `tool-helper`; selected parent directories still
|
||||
normalize within descendant paths. The comparison contract records these rules as
|
||||
`path-component-boundaries-v2`, so captures made with the earlier prefix rules
|
||||
cannot be compared as if the text had the same meaning.
|
||||
|
||||
Rendered frame `lines` hold the visible rows after normalization, with trailing
|
||||
U+0020 spaces removed. Blank rows and internal spaces remain. `columns` records
|
||||
terminal cell width; normalization and Unicode can make string lengths differ
|
||||
@@ -328,6 +342,10 @@ validation is recorded as `unverified` with its reason. Cancellation before any
|
||||
deadline keeps the existing terminal kill. Descendants are not signalled during
|
||||
finalization; owned-process cleanup handles them afterwards.
|
||||
|
||||
For an `exited` capture, `exit.code` is the target's normal exit code. It is
|
||||
`null` when the target ended on a signal, such as one sent by a scenario
|
||||
`signal` event, and the observed signal stays in `exit.signal`.
|
||||
|
||||
`exit.reason` keeps the initiating deadline (`timeout` or `idle_timeout`).
|
||||
`exit.code` is `null` for every deadline exit; the code of an exit observed
|
||||
during finalization is `exit.finalization.exit_code`, and the observed signal
|
||||
|
||||
@@ -6,20 +6,41 @@ MCP. They read archive bytes without launching the application. Bytecode
|
||||
source decompilation, encrypted PYZ recovery, zipapp and PEX analysis are outside
|
||||
this capability.
|
||||
|
||||
`extract_artifact.coverage` preserves the inventory producer's source traversal
|
||||
scope and certainty. Successful publication proves that the selected inventoried
|
||||
regular files were written and verified; it does not prove that every source
|
||||
entry was representable or every embedded payload was decoded. For example, a
|
||||
directory containing an invalid UTF-8 filename can publish its representable
|
||||
files successfully while coverage remains `unknown`. Extraction retains the
|
||||
inventory's command provenance and limitations, plus the selected occurrences'
|
||||
path-qualified derivation notices. A reconstructed `.pyc` header therefore stays
|
||||
identified as derived bytes in the extraction result.
|
||||
|
||||
## Facts and focused queries
|
||||
|
||||
The root occurrence's `format_metadata` records the CArchive layout (2.0 or
|
||||
2.1), archive and cookie offsets, table extent, entry count, raw Python version,
|
||||
normalized major/minor when known, library name and encryption marker. Member
|
||||
metadata retains the original name, table index, type, compression flag,
|
||||
relative offset and known directory record extent. Logical paths use archive
|
||||
path rules; the source name retains its spelling, including backslashes.
|
||||
relative offset and known directory record extent. Logical paths follow the
|
||||
carrier's path dialect: backslashes separate components for PE carriers, while
|
||||
they remain literal filename characters for POSIX carriers. The source name
|
||||
always retains its stored spelling. If the carrier dialect is unconfirmed, REA
|
||||
preserves backslashes verbatim instead of inferring POSIX semantics.
|
||||
`relative_offset` is relative to the CArchive start for CArchive rows, or to
|
||||
the decoded PYZ image for PYZ rows. A CArchive directory record starts at
|
||||
`archive_start + toc_offset + directory_record_offset`; its size is
|
||||
`directory_record_size`. PYZ row directory extents remain unknown.
|
||||
CArchive type `b` retains PyInstaller's executable-member declaration in the
|
||||
generic `executable` fact; type `x` remains non-executable. This comes from the
|
||||
archive type code, not the filename or member contents.
|
||||
Distinct CArchive rows retain their table-index identities even when they
|
||||
share a logical path. Inventory can preserve both a file and a decoded PYZ
|
||||
directory at that path, including the PYZ children; extraction refuses a
|
||||
destination conflict instead of silently omitting those children.
|
||||
|
||||
Namespace packages remain directories. Their `relative_offset` and
|
||||
Namespace packages remain metadata declarations at their projected query path;
|
||||
they do not claim a destination directory. Their `relative_offset` and
|
||||
`compressed_size` preserve any payload declared by older producers, while
|
||||
`declared_size` is zero because no bytecode is materialized for a namespace.
|
||||
Every declared span must end before the PYZ table of contents.
|
||||
@@ -49,6 +70,15 @@ table index; original names remain available in the supplied artifact.
|
||||
Path failures use bounded escaped previews and report the original length;
|
||||
accepted paths and retained source names are not shortened.
|
||||
|
||||
`compare_artifacts` compares these node-less records as declarations using the
|
||||
container, container name, source name and type code. Equal option or dependency
|
||||
declarations can therefore compare unchanged without implying that an external
|
||||
dependency's bytes were found. For materialized PyInstaller members, the same
|
||||
fields participate in the metadata delta independently of content identity;
|
||||
archive offsets and table positions remain location facts, not declaration
|
||||
identity. Missing declaration facts and unavailable non-metadata content remain
|
||||
unknown.
|
||||
|
||||
Request `detail: "summary"` for a compact inspection, then query retained
|
||||
Evidence with `inspect_analysis_view`. An inventory view can select
|
||||
`collection: "occurrences"`, `entry_kinds: ["metadata"]`, exact logical paths or
|
||||
@@ -95,8 +125,15 @@ returns a resource failure.
|
||||
|
||||
Supported final Python bytecode magic values cover Python 3.7 through 3.14.
|
||||
Supported marshal directory values are lists, tuples, strings, integers and
|
||||
bytes. An unsupported magic or directory stays an opaque member with a
|
||||
limitation and `pyz_status: "opaque"`; its module contents remain unknown.
|
||||
bytes, including interned Unicode strings used for module names. Unicode strings
|
||||
use CPython's UTF-8 `surrogatepass` encoding, preserving lone surrogate code
|
||||
points in decoded module names. Directory values follow the identified CPython marshal semantics; for
|
||||
example, a long integer with a zero most-significant digit is malformed and is
|
||||
not normalized into a valid table value. An unsupported magic or malformed or
|
||||
unsupported directory stays an opaque member with a limitation and
|
||||
`pyz_status: "opaque"`; no child entries from that table are projected, and
|
||||
their module contents remain unknown. The original PYZ member and its digest
|
||||
remain available independently. Healthy CArchive siblings are still inventoried.
|
||||
Any opaque PYZ makes producer traversal coverage unknown, including retained
|
||||
summaries and exhausted queries. Per-archive reasons remain on the opaque
|
||||
occurrences; the coverage observation summarizes their count without repeating
|
||||
@@ -107,11 +144,15 @@ The directory declares compressed module lengths, so uncompressed declared
|
||||
sizes and source spans inside decoded data remain unknown.
|
||||
|
||||
PYZ modules receive a derived 16-byte `.pyc` header from their own supported
|
||||
magic. CArchive bytecode receives that header only when every sibling PYZ magic
|
||||
and the cookie's Python version agree. Otherwise it retains its original bytes
|
||||
and `bytecode_header: "unknown"`. `bytecode_magic` and graph derivation edges
|
||||
identify synthesized headers; member digests cover the resulting derived files.
|
||||
These headers do not establish successful execution or decompilation.
|
||||
magic. CArchive scripts receive that header only when every sibling PYZ magic
|
||||
and the cookie's Python version agree. Under the same agreement, CArchive
|
||||
modules (`m`/`M`) receive a header only when their decompressed prefix identifies
|
||||
headerless marshal code. Legacy modules that retain a `.pyc` header, and modules
|
||||
whose prefix is unrecognized, preserve their original bytes and report
|
||||
`bytecode_header: "unknown"`. A header prefix does not establish that the entire
|
||||
file is valid. `bytecode_magic` and graph derivation edges identify synthesized
|
||||
headers; member digests cover the resulting derived files. These headers do not
|
||||
establish successful execution or decompilation.
|
||||
|
||||
The nonempty CArchive Python module `pyimod00_crypto_key` (`m`/`M`) is recorded
|
||||
as an encryption marker; a same-named data file or script is not. Affected
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
# CPython pyc inspection
|
||||
|
||||
`inspect_python_pyc` / `inspect-python-pyc` reports the supported CPython format
|
||||
and version declared by one selected local `.pyc` file's magic, how its 16-byte
|
||||
header records source identity, and which nested code objects its decoded
|
||||
marshal graph contains. It reads the file without running bytecode and requires
|
||||
no Python installation, active binary target, Hopper, Ghidra, or IDA.
|
||||
|
||||
```bash
|
||||
rea inspect-python-pyc /absolute/path/to/module.pyc --json
|
||||
```
|
||||
|
||||
The CLI resolves relative paths against the caller's working directory. MCP
|
||||
requires an absolute filesystem path and preserves that exact selection:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inspect_python_pyc",
|
||||
"arguments": { "path": "/artifacts/module.pyc" }
|
||||
}
|
||||
```
|
||||
|
||||
## Observations
|
||||
|
||||
The inline Evidence result contains the artifact path, SHA-256, and byte length.
|
||||
`header` contains:
|
||||
|
||||
- `magic`, the 16-bit little-endian field;
|
||||
- `python_version` and `code_layout`, mapped from the pinned CPython 3.7–3.13
|
||||
table (`py37`, `py38`, or `py311`); 3.11 alpha magics before 3494 used
|
||||
other code layouts and are unsupported. The 3.7.0a1/a2 magics 3390/3391
|
||||
used 12-byte headers and are outside this reader's supported format;
|
||||
- `flags`, `hash_based`, and `check_source` from PEP 552;
|
||||
- `source_hash_hex` for hash-based pycs, or `source_mtime` and `source_size`
|
||||
for timestamp pycs.
|
||||
|
||||
`code_objects` lists each code object reachable in the decoded marshal graph
|
||||
once, the top-level module code first. This follows CPython container behavior;
|
||||
it is not an inventory of raw serialized code-object records. `nested_code`
|
||||
holds the indexes of the distinct code objects reachable from that object's
|
||||
constants, including code nested in tuples and other containers and the owner
|
||||
itself when a constant container reaches it.
|
||||
A function shared through a marshal reference is named by index once per owner,
|
||||
even when that owner reaches it again through the same container. Relationships
|
||||
are collected after the marshal graph is complete, so a container that a nested
|
||||
code object also references is not summarized while its items are still missing.
|
||||
Each object reports name, optional qualname,
|
||||
filename, the signed 32-bit `co_firstlineno` value, argument counts, flags,
|
||||
names, locals (or `localsplusnames` on 3.11+), const
|
||||
summaries, and bytecode length plus SHA-256.
|
||||
|
||||
Code-object equality used by sets and dictionaries follows the selected CPython format:
|
||||
3.7–3.10 derive `CO_NOFREE` from the free/cell tables for equality, while
|
||||
3.11+ compare raw flags; raw `co_flags` remain in reported facts. The older
|
||||
layouts ignore line tables, while 3.11+ include line and exception tables and
|
||||
skip inline-cache code units according to the cache table for the exact magic.
|
||||
Reported bytecode length and SHA-256 still describe the original code bytes.
|
||||
This does not emulate CPython's deoptimization of specialized or instrumented
|
||||
opcode bytes in handcrafted pyc files.
|
||||
The artifact SHA-256 identifies the exact selected `.pyc` bytes independently
|
||||
of this decoded object graph. Reference slots follow each tag's CPython behavior:
|
||||
singleton values and `TYPE_REF` do not reserve new slots even when their tag
|
||||
has `FLAG_REF` set.
|
||||
|
||||
Reported names are JavaScript display strings; distinct CPython Unicode names
|
||||
can therefore have the same displayed value and cannot always be reconstructed
|
||||
from that field alone. Code equality uses the retained marshal string bytes,
|
||||
while the artifact SHA-256 continues to identify the original file bytes.
|
||||
|
||||
Bytecode is not decompiled. Const strings may be truncated in the summary while
|
||||
the marshal walk still consumed the original bytes; a string summary's `bytes`
|
||||
is that marshal length. Integer consts report `bits`; their decimal `value` is
|
||||
`null` above 256 bits. Non-finite float and complex parts use CPython's `inf`,
|
||||
`-inf`, and `nan` spellings. Dictionary and set lengths follow CPython:
|
||||
unhashable keys and members fail the walk, equal set members count once, equal
|
||||
dictionary keys keep the first key object and replace only its value, code
|
||||
objects are valid keys and members only when all of their consts are hashable,
|
||||
and a null dictionary value ends the dict without that entry.
|
||||
|
||||
## Limits and failures
|
||||
|
||||
The selected file is limited to 16 MiB by default (64 MiB maximum). Marshal
|
||||
object count, nesting depth, and per-string size are bounded; exceeding a
|
||||
budget fails without partial success. Argument counts, positional-only counts,
|
||||
keyword-only counts, and local counts must be non-negative. `co_stacksize` and
|
||||
`co_flags` are retained as signed 32-bit source fields when the selected CPython
|
||||
constructor accepted them. CPython 3.7 and 3.8 alpha constructors through
|
||||
3.8.0a4 did not reject negative stack sizes or flags; the check was added by
|
||||
[CPython commit a9f05d69](https://github.com/python/cpython/commit/a9f05d69ccbf3c75cdd604c25094282697789a62).
|
||||
Magic 3410 is ambiguous: 3.8.0a4 and 3.8.0b1 both use it, but they are on
|
||||
opposite sides of that constructor change. Negative values under magic 3410
|
||||
are preserved with an explicit limitation because the header cannot identify
|
||||
which constructor revision produced them. Magic 3411 and later 3.8 magics were
|
||||
introduced after that change, so their constructors reject negative values.
|
||||
The pinned magic entries distinguish these cases; see the CPython
|
||||
[3.7.0 constructor](https://github.com/python/cpython/blob/v3.7.0/Objects/codeobject.c),
|
||||
[3.8.0a4 constructor](https://github.com/python/cpython/blob/v3.8.0a4/Objects/codeobject.c),
|
||||
[3.8.0b1 constructor](https://github.com/python/cpython/blob/v3.8.0b1/Objects/codeobject.c),
|
||||
and [3.8.0b2 magic table](https://github.com/python/cpython/blob/v3.8.0b2/Lib/importlib/_bootstrap_external.py).
|
||||
Complete marshal coverage means all fields in the selected file were decoded;
|
||||
it does not establish that CPython will accept or execute the code object. On
|
||||
the 3.11+ layout, `co_code` must cover a
|
||||
whole number of code units. Every layout rejects argument counts that do not
|
||||
fit the local table CPython checks (`co_varnames`, including `*args` /
|
||||
`**kwargs`, or fast locals on 3.11+). Those files are malformed, so the
|
||||
workflow does not report complete coverage. 3.7–3.10 still accept an odd
|
||||
`co_code`, matching those constructors. Nested code collection walks reference
|
||||
chains iteratively and keeps one shared descendant list for a container that
|
||||
merely wraps another, instead of copying that list onto every wrapper. Set and
|
||||
dictionary keys walk tuple and frozenset reference chains the same way, so a
|
||||
long `TYPE_REF` chain stays within the call stack. A shared child stored twice
|
||||
still counts its expanded key against the string budget. Code-object equality
|
||||
keys record each name table's length and each entry's boundaries, so `()` and
|
||||
`("",)` stay distinct, and `co_varnames`, `co_freevars`, and `co_cellvars` stay
|
||||
separate tables. Names repeated through a marshal reference, including each
|
||||
code-constant name the report copies, count against the file budget once per
|
||||
copy. Empty strings add no bytes, so every copied
|
||||
name-table entry (`co_names`, varnames, freevars, cellvars, and
|
||||
`localsplusnames`) counts against the object budget before its array is built.
|
||||
Copied constant tables and each reported nested code relationship count
|
||||
against that same object budget. Integer digits and expanded
|
||||
set or dictionary keys, including a shared tuple repeated at each level, count
|
||||
against the string budget. Magics outside the pinned 3.7–3.13 table,
|
||||
truncated headers, trailing marshal bytes, and a non-code top-level object are
|
||||
typed failures.
|
||||
|
||||
A decoded header does not prove the matching `.py` is present. `python_version`
|
||||
is the magic table, not a running interpreter. This workflow does not recover
|
||||
source.
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · **العربية** · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: هندسة عكسية لأي شيء
|
||||
|
||||
@@ -137,14 +137,17 @@ npx rea-agents@latest setup
|
||||
|
||||
## ما الذي يمكنك تحليله
|
||||
|
||||
يتطلب REA إصدار Node.js 22.x (>=22.19) أو 24.x (>=24.11) أو 26+، إضافة إلى npm. تعتمد الأدوات الإضافية والأنظمة المضيفة المدعومة على الهدف:
|
||||
يتطلب REA إصدار Node.js 22.x (>=22.23.4) أو 24.x (>=24.22.1) أو 26+ (>=26.12.1)، إضافة إلى npm. تعتمد الأدوات الإضافية والأنظمة المضيفة المدعومة على الهدف:
|
||||
|
||||
| الهدف | ما يعيده REA | المتطلبات والدليل |
|
||||
| ------------------------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
||||
| الملفات الثنائية للشيفرة الأصلية | شيفرة شبه برمجية، وتعليمات تجميع، وسلاسل نصية، ورموز، واستدعاءات، ومراجع | Hopper أو Ghidra أو IDA؛ [تحليل الشيفرة الأصلية](../native-investigation.md) |
|
||||
| بنية ELF دون تشغيل | الأقسام والمقاطع والرموز ومعلومات إعادة التموضع الأصلية، وآليات الحماية المحتملة المستدلّ عليها بالفحص الثابت | pwntools يوفّره المستدعي على Linux x64؛ [تشخيص الملفات الثنائية](../binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| شيفرة EVM البايتية | محددات التوجيه، وإزاحات البايتات، والمعاملات المستنتجة، وقابلية تغيير الحالة | مدخل محلي يحمل بايتات خامًا أو تمثيلًا سداسيًا عشريًا على Linux x64؛ [دليل EVM دون تشغيل](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| أعطال Linux المسجّلة | سجلات note الخام، ومسجّلات المعالج/الإشارات لكل خيط مسجّل، وترشيحات اختيارية لخرائط الذاكرة | pwntools يوفّره المستدعي على Linux x64؛ GDB/pwndbg اختياريان؛ [الأعطال المسجّلة](../recorded-crashes.md) |
|
||||
| تثبيتات سطح المكتب | عائلات وقت التشغيل، والملفات الداعمة، وعلامات المكونات، والخطوات التالية | فحص محدود للملفات والترويسات;[تطبيقات سطح المكتب](../desktop-applications.md) |
|
||||
| JavaScript / Electron | الوحدات، وعمليات الاستيراد، وخرائط المصدر، والمسارات، وIPC، وعلاقات إضافات الشيفرة الأصلية | Node.js وnpm؛ [تحليل التطبيقات](../javascript-application-workflows.md) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · **Deutsch** · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: Alles reverse-engineeren
|
||||
|
||||
@@ -137,14 +137,17 @@ Dein Agent ruft REA über MCP auf, um das Ziel zu untersuchen und relevanten Cod
|
||||
|
||||
## Was du analysieren kannst
|
||||
|
||||
REA benötigt Node.js 22.x (>=22.19), 24.x (>=24.11) oder 26+ sowie npm. Zusätzliche Werkzeuge und unterstützte Hostsysteme hängen vom Ziel ab:
|
||||
REA benötigt Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) oder 26+ (>=26.12.1) sowie npm. Zusätzliche Werkzeuge und unterstützte Hostsysteme hängen vom Ziel ab:
|
||||
|
||||
| Ziel | Was REA zurückgibt | Voraussetzungen und Anleitung |
|
||||
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Native Binärdateien | Pseudocode, Assemblercode, Zeichenketten, Symbole, Aufrufe und Verweise | Hopper, Ghidra oder IDA; [native Analyse](../native-investigation.md) |
|
||||
| Offline-ELF-Struktur | Sektionen, Segmente, ursprüngliche Symbole/Relokationen und mögliche Schutzmaßnahmen aus statischer Analyse | Vom Aufrufer bereitgestelltes pwntools unter Linux x64; [Binärdiagnostik](../binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| EVM-Bytecode | Dispatch-Selektoren, Byte-Offsets, abgeleitete Argumente und Veränderbarkeit des Zustands | Lokale Eingabe mit Rohbytes oder Hexdarstellung unter Linux x64; [Offline-EVM-Leitfaden](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| Aufgezeichnete Linux-Abstürze | Unverarbeitete Note-Einträge, Register/Signale aller aufgezeichneten Threads und optionale Zuordnungskandidaten | Vom Aufrufer bereitgestelltes pwntools unter Linux x64; optional GDB/pwndbg; [aufgezeichnete Abstürze](../recorded-crashes.md) |
|
||||
| Desktop-Installationen | Laufzeitkandidaten, Quelldateien, Komponenten und nächste Schritte | Begrenzte Verzeichnis- und Headerprüfung;[Desktop-Anwendungen](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Module, Imports, Source Maps, Routen, IPC und Beziehungen zu nativen Add-ons | Node.js und npm; [Anwendungsanalyse](../javascript-application-workflows.md) |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md) · **Ελληνικά** · [മലയാളം](README_ml.md)
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md) · **Ελληνικά** · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -141,7 +141,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## Τι μπορείς να αναλύσεις
|
||||
|
||||
Το REA απαιτεί Node.js 22.x (>=22.19), 24.x (>=24.11) ή 26+, καθώς και npm. Τα πρόσθετα εργαλεία και τα υποστηριζόμενα συστήματα εξαρτώνται από τον στόχο:
|
||||
Το REA απαιτεί Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) ή 26+ (>=26.12.1), καθώς και npm. Τα πρόσθετα εργαλεία και τα υποστηριζόμενα συστήματα εξαρτώνται από τον στόχο:
|
||||
|
||||
| Στόχος | Τι επιστρέφει το REA | Απαιτήσεις και οδηγός |
|
||||
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -149,6 +149,9 @@ npx rea-agents@latest setup
|
||||
| Δομή ELF χωρίς εκτέλεση | Ενότητες, τμήματα, αρχικά σύμβολα/εγγραφές μετεγκατάστασης και ενδείξεις πιθανών μέτρων προστασίας από στατική ανάλυση | pwntools που παρέχει ο χρήστης σε Linux x64· [διαγνωστικά δυαδικών αρχείων](../binary-diagnostics.md) |
|
||||
| Δυαδικά αρχεία Go | Ενσωματωμένη έκδοση μεταγλωττιστή, modules, αντικαταστάσεις και ρυθμίσεις μεταγλώττισης | Ενσωματωμένη στατική εξέταση ELF/PE/thin Mach-O· δεν απαιτείται εγκατάσταση του Go |
|
||||
| Δυαδικά αρχεία Rust | Ενσωματωμένα ονόματα, εκδόσεις, πηγές και σχέσεις εξάρτησης των crates από το cargo-auditable | Ενσωματωμένη στατική εξέταση ELF/PE/thin Mach-O· [δυαδικά αρχεία Rust](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| Αρχείο WASM | Έλεγχο εγκυρότητας, ενότητες, ακριβείς μορφές εισαγωγών/εξαγωγών σε WAT και αποκωδικοποιημένο WAT | WABT 1.0.42 που παρέχει ο χρήστης· `inspect_wasm_artifact` |
|
||||
| Bytecode EVM | Selectors επιλογής συνάρτησης, μετατοπίσεις σε bytes, εκτιμώμενα ορίσματα και δυνατότητα μεταβολής της κατάστασης | Τοπική είσοδος σε ακατέργαστα bytes ή δεκαεξαδική μορφή σε Linux x64· [οδηγός EVM χωρίς εκτέλεση](../evm-bytecode.md) |
|
||||
| Βάσεις δεδομένων SQLite | Πίνακες, στήλες, ευρετήρια, όψεις, triggers και επιλεγμένες γραμμές κανονικών πινάκων | Τοπικό στιγμιότυπο βάσης δεδομένων/WAL· Node.js 24.x >=24.15 ή 26+ με εγγενή όρια SQLite |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · **Español** · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: Ingeniería inversa de cualquier cosa
|
||||
|
||||
@@ -137,14 +137,17 @@ Tu agente llama a REA mediante MCP para inspeccionar el objetivo y seguir el có
|
||||
|
||||
## Qué puedes analizar
|
||||
|
||||
REA requiere Node.js 22.x (>=22.19), 24.x (>=24.11) o 26+, además de npm. Las herramientas adicionales y los sistemas anfitriones compatibles dependen del objetivo:
|
||||
REA requiere Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) o 26+ (>=26.12.1), además de npm. Las herramientas adicionales y los sistemas anfitriones compatibles dependen del objetivo:
|
||||
|
||||
| Objetivo | Qué devuelve REA | Requisitos y guía |
|
||||
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Binarios nativos | Pseudocódigo, ensamblador, cadenas, símbolos, llamadas y referencias | Hopper, Ghidra o IDA; [análisis nativo](../native-investigation.md) |
|
||||
| Estructura ELF sin ejecutar | Secciones, segmentos, símbolos/reubicaciones originales y posibles medidas de mitigación detectadas mediante análisis estático | pwntools proporcionado por quien llama, en Linux x64; [diagnóstico de binarios](../binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| Bytecode EVM | Selectores de despacho, desplazamientos en bytes, argumentos inferidos y mutabilidad | Entrada local con bytes sin procesar o representación hexadecimal, en Linux x64; [guía de EVM sin ejecutar](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| Fallos de Linux registrados | Registros note sin procesar, registros/señales de cada hilo registrado y posibles correspondencias de memoria opcionales | pwntools proporcionado por quien llama, en Linux x64; GDB/pwndbg opcionales; [fallos registrados](../recorded-crashes.md) |
|
||||
| Instalaciones de escritorio | Posibles entornos de ejecución, archivos de evidencia, componentes y siguientes pasos | Inspección acotada de directorios y cabeceras;[Aplicaciones de escritorio](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Módulos, importaciones, mapas de código fuente, rutas, IPC y relaciones con complementos nativos | Node.js y npm; [análisis de aplicaciones](../javascript-application-workflows.md) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center" dir="rtl">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · **فارسی** · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: مهندسی معکوس هر چیزی
|
||||
|
||||
@@ -129,14 +129,17 @@ npx rea-agents@latest setup
|
||||
|
||||
## چه چیزهایی را میتوان تحلیل کرد؟
|
||||
|
||||
REA به Node.js 22.x (>=22.19)، 24.x (>=24.11) یا 26+، بههمراه npm نیاز دارد. ابزارهای اضافی و پشتیبانی سیستم میزبان به نوع هدف بستگی دارند:
|
||||
REA به Node.js 22.x (>=22.23.4)، 24.x (>=24.22.1) یا 26+ (>=26.12.1)، بههمراه npm نیاز دارد. ابزارهای اضافی و پشتیبانی سیستم میزبان به نوع هدف بستگی دارند:
|
||||
|
||||
| هدف | خروجی REA | پیشنیازها و راهنما |
|
||||
| ---------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| باینریهای بومی | شبهکد، اسمبلی، رشتهها، نمادها، فراخوانیها و ارجاعات | Hopper، Ghidra یا IDA؛ [تحلیل بومی](../native-investigation.md) |
|
||||
| ساختار ELF آفلاین | بخشها، سگمنتها، نمادها و relocationهای اصلی و گزینههای احتمالی کاهش آسیبپذیری ایستا | pwntools تأمینشده توسط فراخواننده روی Linux x64؛ [تشخیص باینری](../binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| بایتکد EVM | selectorهای dispatch، offsetهای بایتی، آرگومانهای استنباطشده و قابلیت تغییر وضعیت | دادهٔ خام/hex محلی روی Linux x64؛ [راهنمای EVM آفلاین](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| کرشهای ثبتشدهٔ لینوکس | یادداشتهای خام، رجیسترها/سیگنالهای تمام threadهای ثبتشده و گزینههای احتمالی نگاشت | pwntools تأمینشده توسط فراخواننده روی Linux x64؛ GDB/pwndbg اختیاری؛ [کرشهای ثبتشده](../recorded-crashes.md) |
|
||||
| نصبهای دسکتاپ | نامزدهای زمان اجرا، فایلهای شاهد، نشانههای مؤلفهها و مراحل بعدی | بررسی محدود پوشهها و سرآیندها;[برنامههای دسکتاپ](../desktop-applications.md) |
|
||||
| JavaScript / Electron | ماژولها، importها، source mapها، مسیرها، IPC و ارتباط افزونههای بومی | Node.js و npm؛ [تحلیل برنامه](../javascript-application-workflows.md) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · **Français** · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA : rétro-ingénierie de tout
|
||||
|
||||
@@ -140,15 +140,18 @@ Votre agent appelle REA via MCP pour inspecter la cible et suivre le code pertin
|
||||
|
||||
## Ce que vous pouvez analyser
|
||||
|
||||
REA nécessite Node.js 22.x (>=22.19), 24.x (>=24.11) ou 26+, ainsi que npm. Les outils supplémentaires et les hôtes pris en charge dépendent de la cible :
|
||||
REA nécessite Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) ou 26+ (>=26.12.1), ainsi que npm. Les outils supplémentaires et les hôtes pris en charge dépendent de la cible :
|
||||
|
||||
| Cible | Ce que REA renvoie | Prérequis et guide |
|
||||
| ---------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Binaires natifs | Pseudo-code, assembleur, chaînes, symboles, appels et références | Hopper, Ghidra ou IDA ; [analyse native](../native-investigation.md) |
|
||||
| Structure ELF hors ligne | Sections, segments, symboles et relocations d'origine, et protections statiques candidates | pwntools fourni par l'utilisateur sous Linux x64 ; [diagnostics binaires](../binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| Artefact WASM | Validation, sections, formes WAT exactes d'import/export et WAT décodé | WABT 1.0.42 fourni par l'utilisateur ; `inspect_wasm_artifact` |
|
||||
| Bytecode EVM | Sélecteurs de dispatch, offsets en octets, arguments inférés et mutabilité | Fichier local brut ou hexadécimal sous Linux x64 ; [guide EVM hors ligne](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| Crashs Linux enregistrés | Notes brutes, registres et signaux de chaque thread enregistré, et correspondances de mappings facultatives | pwntools fourni par l'utilisateur sous Linux x64 ; GDB/pwndbg en option ; [crashs enregistrés](../recorded-crashes.md) |
|
||||
| Installations de bureau | Environnements candidats, fichiers justificatifs, composants et étapes suivantes | Inspection bornée des répertoires et en-têtes;[Applications de bureau](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Modules, imports, source maps, routes, IPC et relations avec les modules natifs | Node.js et npm ; [analyse d'applications](../javascript-application-workflows.md) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · **Bahasa Indonesia** · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: Rekayasa Balik Apa Pun
|
||||
|
||||
@@ -141,7 +141,7 @@ Perintah CLI menggunakan alur kerja yang sama.
|
||||
|
||||
## Hal yang Dapat Anda Analisis
|
||||
|
||||
REA memerlukan Node.js 22.x (>=22.19), 24.x (>=24.11), atau 26+, beserta npm.
|
||||
REA memerlukan Node.js 22.x (>=22.23.4), 24.x (>=24.22.1), atau 26+ (>=26.12.1), beserta npm.
|
||||
|
||||
Alat tambahan dan dukungan sistem host bergantung pada target yang dianalisis:
|
||||
|
||||
@@ -149,9 +149,12 @@ Alat tambahan dan dukungan sistem host bergantung pada target yang dianalisis:
|
||||
| -------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Biner native | Pseudocode, assembly, string, simbol, pemanggilan, dan referensi | Hopper, Ghidra, atau IDA; [analisis native](../native-investigation.md) |
|
||||
| Tata letak ELF offline | Bagian, segmen, simbol/relokasi asli, dan kandidat mitigasi statis | pwntools yang disediakan pemanggil pada Linux x64; [diagnostik biner](../binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| Artefak WASM | Validasi, bagian, bentuk WAT import/ekspor yang tepat, dan WAT yang didekode | WABT 1.0.42 yang disediakan pemanggil; `inspect_wasm_artifact` |
|
||||
| Bytecode EVM | Selector dispatch, offset byte, argumen yang disimpulkan, dan sifat mutabilitas | Pembawa data raw/hex lokal; [panduan EVM offline](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| Crash Linux yang direkam | Catatan mentah, register/sinyal setiap thread yang direkam, dan kandidat pemetaan opsional | pwntools yang disediakan pemanggil; GDB/pwndbg opsional; [crash yang direkam](../recorded-crashes.md) |
|
||||
| Instalasi desktop | Kandidat runtime, berkas pendukung, penanda komponen, dan langkah berikutnya | Pemeriksaan direktori dan header terbatas;[Aplikasi desktop](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Modul, impor, source map, rute, IPC, dan hubungan add-on native | Node.js dan npm; [analisis aplikasi](../javascript-application-workflows.md) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · **Italiano**
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -140,15 +140,18 @@ Il tuo agente chiama REA tramite MCP per ispezionare il bersaglio e tracciare il
|
||||
|
||||
## Cosa puoi analizzare
|
||||
|
||||
REA richiede Node.js 22.x (>=22.19), 24.x (>=24.11) o 26+, oltre a npm. Strumenti aggiuntivi e supporto host dipendono dal bersaglio:
|
||||
REA richiede Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) o 26+ (>=26.12.1), oltre a npm. Strumenti aggiuntivi e supporto host dipendono dal bersaglio:
|
||||
|
||||
| Obiettivo | Cosa restituisce REA | Requisiti e guida |
|
||||
| ---------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Binari nativi | Pseudocodice, assembly, stringhe, simboli, chiamate e riferimenti | Hopper, Ghidra o IDA; [analisi nativa](../native-investigation.md) |
|
||||
| Layout ELF offline | Sezioni, segmenti, simboli/relocazioni originali e candidati mitigazioni statiche | pwntools fornito dal chiamante su Linux x64; [diagnostica binaria](../binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| Artefatto WASM | Convalida, sezioni, forme WAT di import/export esatte e WAT decodificato | WABT 1.0.42 fornito dal chiamante; `inspect_wasm_artifact` |
|
||||
| Bytecode EVM | Selettori di dispatch, offset dei byte, argomenti inferiti e mutabilità | Carrier raw/hex locale; [guida EVM offline](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| Crash Linux registrati | Note grezze, registri/segnai di ogni thread registrato e candidati mapping opzionali | pwntools fornito dal chiamante; GDB/pwndbg opzionale; [crash registrati](../recorded-crashes.md) |
|
||||
| Installazioni desktop | Runtime candidati, file di supporto, componenti e passi successivi | Ispezione limitata di directory e intestazioni;[Applicazioni desktop](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Moduli, import, source map, route, IPC e relazioni con add-on nativi | Node.js e npm; [analisi delle applicazioni](../javascript-application-workflows.md) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · **日本語** · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA:あらゆるものをリバースエンジニアリング
|
||||
|
||||
@@ -137,14 +137,17 @@ npx rea-agents@latest setup
|
||||
|
||||
## 分析できる対象
|
||||
|
||||
REA には Node.js 22.x(>=22.19)、24.x(>=24.11)、または 26+ と npm が必要です。追加のツールや対応ホストは、対象によって異なります。
|
||||
REA には Node.js 22.x(>=22.23.4)、24.x(>=24.22.1)、または 26+ (>=26.12.1) と npm が必要です。追加のツールや対応ホストは、対象によって異なります。
|
||||
|
||||
| 対象 | REA が返すもの | 要件とガイド |
|
||||
| -------------------------------- | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| ネイティブバイナリ | 疑似コード、アセンブリ、文字列、シンボル、呼び出し、参照 | Hopper、Ghidra、または IDA;[ネイティブ分析](../native-investigation.md) |
|
||||
| オフライン ELF レイアウト | セクション、セグメント、元のシンボル/再配置情報、静的解析によるセキュリティ対策の候補 | Linux x64 で利用者が用意する pwntools;[バイナリ診断](../binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| EVM バイトコード | ディスパッチセレクター、バイトオフセット、推定された引数と状態変更の可否 | Linux x64 上のローカルの生バイト/16 進数の入力ファイル;[オフライン EVM ガイド](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| 記録済みの Linux クラッシュ | 生の note レコード、記録された全スレッドのレジスター/シグナル、任意のマッピング候補 | Linux x64 で利用者が用意する pwntools;GDB/pwndbg は任意;[記録済みクラッシュ](../recorded-crashes.md) |
|
||||
| デスクトップのインストール先 | ランタイム候補、根拠ファイル、コンポーネントの目印、次の調査手順 | 上限付きのディレクトリ・ヘッダー検査;[デスクトップアプリ](../desktop-applications.md) |
|
||||
| JavaScript / Electron | モジュール、インポート、ソースマップ、ルート、IPC、ネイティブアドオンの関係 | Node.js と npm;[アプリケーション分析](../javascript-application-workflows.md) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · **한국어** · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: 무엇이든 리버스 엔지니어링
|
||||
|
||||
@@ -145,7 +145,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## 분석할 수 있는 대상
|
||||
|
||||
REA에는 Node.js 22.x(>=22.19), 24.x(>=24.11) 또는 26+와 npm이 필요합니다. 추가 도구와 호스트 지원은 대상에 따라 다릅니다.
|
||||
REA에는 Node.js 22.x(>=22.23.4), 24.x(>=24.22.1) 또는 26+ (>=26.12.1)와 npm이 필요합니다. 추가 도구와 호스트 지원은 대상에 따라 다릅니다.
|
||||
|
||||
| 대상 | REA가 반환하는 내용 | 요구 사항 및 가이드 |
|
||||
| ---------------------- | ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -153,6 +153,9 @@ REA에는 Node.js 22.x(>=22.19), 24.x(>=24.11) 또는 26+와 npm이 필요합니
|
||||
| 오프라인 ELF 레이아웃 | 섹션, 세그먼트, 원본 심볼/재배치 정보, 정적 분석으로 얻은 보안 완화 기법 후보 | Linux x64에서 호출자가 제공하는 pwntools; [바이너리 진단](../binary-diagnostics.md) |
|
||||
| Go 바이너리 | 내장된 컴파일러 버전, 모듈, `replace` 지시어, 빌드 설정 | REA 내장 ELF/PE/thin Mach-O 정적 검사; Go 설치 불필요 |
|
||||
| Rust 바이너리 | cargo-auditable이 내장한 크레이트 이름, 버전, 소스, 의존성 관계 | REA 내장 ELF/PE/thin Mach-O 정적 검사; [Rust 바이너리](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| WASM 아티팩트 | 유효성 검사, 섹션, import/export의 정확한 WAT 형식, 디코딩된 WAT | 호출자 제공 WABT 1.0.42; `inspect_wasm_artifact` |
|
||||
| EVM 바이트코드 | 디스패치 선택자, 바이트 오프셋, 추론한 인자와 상태 변경 가능 여부 | Linux x64의 로컬 원시 바이트/16진수 입력 파일; [오프라인 EVM 가이드](../evm-bytecode.md) |
|
||||
| SQLite 데이터베이스 | 테이블, 열, 인덱스, 뷰, 트리거, 선택한 일반 테이블의 행 | 로컬 데이터베이스/WAL 스냅샷; Node.js 24.15 이상의 24.x 또는 26 이상(네이티브 SQLite 한도 적용) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · **മലയാളം**
|
||||
· [Ελληνικά](README_el.md) · **മലയാളം** · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: എന്തും Reverse Engineer ചെയ്യുക
|
||||
|
||||
@@ -143,7 +143,7 @@ Target പരിശോധിക്കാനും പ്രസക്തമായ
|
||||
|
||||
## എന്തൊക്കെ വിശകലനം ചെയ്യാം
|
||||
|
||||
REA-യ്ക്ക് Node.js 22.x (>=22.19), 24.x (>=24.11), അല്ലെങ്കിൽ 26+ പതിപ്പും npm-ഉം ആവശ്യമാണ്. Target അനുസരിച്ച് അധിക tools-ഉം host support-ഉം വ്യത്യാസപ്പെടും:
|
||||
REA-യ്ക്ക് Node.js 22.x (>=22.23.4), 24.x (>=24.22.1), അല്ലെങ്കിൽ 26+ (>=26.12.1) പതിപ്പും npm-ഉം ആവശ്യമാണ്. Target അനുസരിച്ച് അധിക tools-ഉം host support-ഉം വ്യത്യാസപ്പെടും:
|
||||
|
||||
| Target | REA നൽകുന്ന ഫലങ്ങൾ | ആവശ്യകതകളും ഗൈഡും |
|
||||
| ---------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -151,6 +151,9 @@ REA-യ്ക്ക് Node.js 22.x (>=22.19), 24.x (>=24.11), അല്ലെ
|
||||
| Offline ELF layout | Sections, segments, യഥാർത്ഥ symbols/relocations, static mitigation candidates | Linux x64-ൽ caller നൽകുന്ന pwntools; [binary diagnostics](../binary-diagnostics.md) |
|
||||
| Go binaries | ഉൾച്ചേർത്ത compiler version, modules, replacements, build settings | Built-in static ELF/PE/thin Mach-O പരിശോധന; Go installation ആവശ്യമില്ല |
|
||||
| Rust binaries | ഉൾച്ചേർത്ത cargo-auditable crate പേരുകൾ, versions, sources, dependency edges | Built-in static ELF/PE/thin Mach-O പരിശോധന; [Rust binaries](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| WASM artifact | Validation, sections, കൃത്യമായ import/export WAT രൂപങ്ങൾ, decoded WAT | Caller നൽകുന്ന WABT 1.0.42; `inspect_wasm_artifact` |
|
||||
| EVM bytecode | Dispatch selectors, byte offsets, അനുമാനിച്ച arguments, mutability | Linux x64-ൽ local raw/hex carrier; [offline EVM guide](../evm-bytecode.md) |
|
||||
| SQLite databases | Tables, columns, indexes, views, triggers, തിരഞ്ഞെടുത്ത സാധാരണ table rows | Local database/WAL snapshot; native SQLite പരിമിതികളോടെ Node.js 24.x >=24.15 അല്ലെങ്കിൽ 26+ |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · **Polski** · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -137,14 +137,17 @@ Twój agent wywołuje REA przez MCP, aby analizować cel i śledzić istotny kod
|
||||
|
||||
## Co możesz analizować
|
||||
|
||||
REA wymaga Node.js 22.x (>=22.19), 24.x (>=24.11) lub 26+ oraz npm. Dodatkowe narzędzia i obsługiwane platformy zależą od celu analizy:
|
||||
REA wymaga Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) lub 26+ (>=26.12.1) oraz npm. Dodatkowe narzędzia i obsługiwane platformy zależą od celu analizy:
|
||||
|
||||
| Cel | Co zwraca REA | Wymagania i przewodnik |
|
||||
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Natywne pliki binarne | Pseudokod, kod asemblera, ciągi znaków, symbole, wywołania i odwołania | Hopper, Ghidra lub IDA; [analiza kodu natywnego](../native-investigation.md) |
|
||||
| Układ pliku ELF w trybie offline | Sekcje, segmenty, oryginalne symbole/relokacje i potencjalne mechanizmy zabezpieczeń wskazane przez analizę statyczną | pwntools dostarczone przez użytkownika w systemie Linux x64; [diagnostyka plików binarnych](../binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| Kod bajtowy EVM | Selektory wywołań, przesunięcia bajtowe, wywnioskowane argumenty i mutowalność | Lokalny plik z surowymi bajtami lub zapisem szesnastkowym w systemie Linux x64; [przewodnik EVM offline](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| Zarejestrowane awarie systemu Linux | Surowe rekordy note, rejestry/sygnały każdego zarejestrowanego wątku i opcjonalni kandydaci na mapowania | pwntools dostarczone przez użytkownika w systemie Linux x64; opcjonalnie GDB/pwndbg; [zarejestrowane awarie](../recorded-crashes.md) |
|
||||
| Instalacje desktopowe | Kandydaci środowisk uruchomieniowych, pliki źródłowe dowodów, komponenty i dalsze kroki | Ograniczona inspekcja katalogów i nagłówków;[Aplikacje desktopowe](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Moduły, importy, mapy źródeł, trasy, IPC i powiązania z natywnymi dodatkami | Node.js i npm; [analiza aplikacji](../javascript-application-workflows.md) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · **Português (Brasil)** · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: Faça engenharia reversa de qualquer coisa
|
||||
|
||||
@@ -137,14 +137,17 @@ Seu agente chama o REA por MCP para inspecionar o alvo e rastrear o código rele
|
||||
|
||||
## O que você pode analisar
|
||||
|
||||
O REA requer Node.js 22.x (>=22.19), 24.x (>=24.11) ou 26+, além do npm. As ferramentas adicionais e os sistemas anfitriões compatíveis dependem do alvo:
|
||||
O REA requer Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) ou 26+ (>=26.12.1), além do npm. As ferramentas adicionais e os sistemas anfitriões compatíveis dependem do alvo:
|
||||
|
||||
| Alvo | O que o REA retorna | Requisitos e guia |
|
||||
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Binários nativos | Pseudocódigo, assembly, strings, símbolos, chamadas e referências | Hopper, Ghidra ou IDA; [análise nativa](../native-investigation.md) |
|
||||
| Estrutura ELF sem execução | Seções, segmentos, símbolos/relocações originais e possíveis mecanismos de mitigação identificados por análise estática | pwntools fornecido pelo chamador no Linux x64; [diagnóstico de binários](../binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| Bytecode EVM | Seletores de despacho, offsets de bytes, argumentos inferidos e mutabilidade | Entrada local com bytes brutos ou representação hexadecimal no Linux x64; [guia de EVM sem execução](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| Falhas do Linux registradas | Registros note brutos, registradores/sinais de cada thread registrada e candidatos opcionais a mapeamentos | pwntools fornecido pelo chamador no Linux x64; GDB/pwndbg opcionais; [falhas registradas](../recorded-crashes.md) |
|
||||
| Instalações desktop | Ambientes candidatos, arquivos de evidência, componentes e próximos passos | Inspeção limitada de diretórios e cabeçalhos;[Aplicações desktop](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Módulos, importações, source maps, rotas, IPC e relações com complementos nativos | Node.js e npm; [análise de aplicativos](../javascript-application-workflows.md) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · **Русский** · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: Реверс-инжиниринг чего угодно
|
||||
|
||||
@@ -137,7 +137,7 @@ npx rea-agents@latest setup
|
||||
|
||||
## Что можно анализировать
|
||||
|
||||
REA требует Node.js 22.x (>=22.19), 24.x (>=24.11) или 26+, а также npm. Дополнительные инструменты и поддерживаемые системы зависят от цели:
|
||||
REA требует Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) или 26+ (>=26.12.1), а также npm. Дополнительные инструменты и поддерживаемые системы зависят от цели:
|
||||
|
||||
| Цель | Что возвращает REA | Требования и руководство |
|
||||
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -145,6 +145,9 @@ REA требует Node.js 22.x (>=22.19), 24.x (>=24.11) или 26+, а так
|
||||
| Структура ELF без запуска | Секции, сегменты, исходные символы/релокации и возможные механизмы защиты по данным статического анализа | pwntools, предоставленный вызывающей стороной, в Linux x64; [диагностика бинарных файлов](../binary-diagnostics.md) |
|
||||
| Байт-код EVM | Селекторы диспетчеризации, смещения байтов, предполагаемые аргументы и изменяемость состояния | Локальные необработанные байты или шестнадцатеричное представление в Linux x64; [руководство по EVM без запуска](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| Записанные сбои Linux | Необработанные записи note, регистры/сигналы каждого записанного потока и необязательные кандидаты сопоставления с памятью | pwntools, предоставленный вызывающей стороной, в Linux x64; необязательные GDB/pwndbg; [записанные сбои](../recorded-crashes.md) |
|
||||
| Установленные настольные приложения | Возможные среды выполнения, файлы с доказательствами, компоненты и дальнейшие шаги | Ограниченная проверка каталогов и заголовков;[Настольные приложения](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Модули, импорты, карты исходного кода, маршруты, IPC и связи с нативными дополнениями | Node.js и npm; [анализ приложений](../javascript-application-workflows.md) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · **ไทย** · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
@@ -137,14 +137,17 @@ npx rea-agents@latest setup
|
||||
|
||||
## สิ่งที่วิเคราะห์ได้
|
||||
|
||||
REA ต้องใช้ Node.js 22.x (>=22.19), 24.x (>=24.11) หรือ 26+ และ npm เครื่องมือเพิ่มเติมและแพลตฟอร์มที่รองรับขึ้นอยู่กับเป้าหมาย:
|
||||
REA ต้องใช้ Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) หรือ 26+ (>=26.12.1) และ npm เครื่องมือเพิ่มเติมและแพลตฟอร์มที่รองรับขึ้นอยู่กับเป้าหมาย:
|
||||
|
||||
| เป้าหมาย | สิ่งที่ REA ส่งกลับ | ข้อกำหนดและคู่มือ |
|
||||
| ---------------------------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
||||
| ไบนารีเนทีฟ | โค้ดเทียม แอสเซมบลี สตริง สัญลักษณ์ การเรียก และการอ้างอิง | Hopper, Ghidra หรือ IDA; [การวิเคราะห์เนทีฟ](../native-investigation.md) |
|
||||
| โครงสร้าง ELF แบบออฟไลน์ | เซกชัน เซกเมนต์ สัญลักษณ์/รีโลเคชันต้นฉบับ และตัวเลือกกลไกป้องกันที่พบจากการวิเคราะห์แบบสถิต | pwntools ที่ผู้ใช้จัดเตรียมบน Linux x64; [การวินิจฉัยไบนารี](../binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| ไบต์โค้ด EVM | ตัวเลือกฟังก์ชันสำหรับการเรียก ออฟเซ็ตไบต์ อาร์กิวเมนต์และความสามารถในการเปลี่ยนสถานะที่อนุมานได้ | ไฟล์บนเครื่องที่มีไบต์ดิบหรือข้อมูลเลขฐานสิบหกบน Linux x64; [คู่มือ EVM แบบออฟไลน์](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| ข้อมูลการแครชของ Linux ที่บันทึกไว้ | ระเบียน note ดิบ รีจิสเตอร์/สัญญาณของทุกเธรดที่บันทึกไว้ และตัวเลือกการแมปเพิ่มเติม | pwntools ที่ผู้ใช้จัดเตรียมบน Linux x64; เลือกใช้ GDB/pwndbg เพิ่มเติมได้; [การแครชที่บันทึกไว้](../recorded-crashes.md) |
|
||||
| ไดเรกทอรีติดตั้งแอปเดสก์ท็อป | รันไทม์ที่เป็นไปได้ ไฟล์หลักฐาน ตัวบ่งชี้ส่วนประกอบ และขั้นตอนถัดไป | ตรวจสอบไดเรกทอรีและส่วนหัวโดยจำกัดขอบเขต;[แอปเดสก์ท็อป](../desktop-applications.md) |
|
||||
| JavaScript / Electron | โมดูล การนำเข้า ซอร์สแมป เส้นทาง IPC และความสัมพันธ์กับส่วนเสริมเนทีฟ | Node.js และ npm; [การวิเคราะห์แอปพลิเคชัน](../javascript-application-workflows.md) |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · **Türkçe** · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: Her şeyi tersine mühendislikle inceleyin
|
||||
|
||||
@@ -139,7 +139,7 @@ Ajanınız, hedefi incelemek ve ilgili kodu izlemek için MCP üzerinden REA'yı
|
||||
|
||||
## Neleri analiz edebilirsiniz
|
||||
|
||||
REA; Node.js 22.x (>=22.19), 24.x (>=24.11) veya 26+ ve npm gerektirir. Ek araçlar ve desteklenen ana bilgisayar sistemleri hedefe bağlıdır:
|
||||
REA; Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) veya 26+ (>=26.12.1) ve npm gerektirir. Ek araçlar ve desteklenen ana bilgisayar sistemleri hedefe bağlıdır:
|
||||
|
||||
| Hedef | REA'nın döndürdükleri | Gereksinimler ve rehber |
|
||||
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -147,6 +147,9 @@ REA; Node.js 22.x (>=22.19), 24.x (>=24.11) veya 26+ ve npm gerektirir. Ek araç
|
||||
| Çevrimdışı ELF yapısı | Bölümler, segmentler, özgün semboller/yeniden konumlandırmalar ve statik analizden olası güvenlik önlemleri | Linux x64 üzerinde çağıranın sağladığı pwntools; [ikili dosya tanılama](../binary-diagnostics.md) |
|
||||
| Go ikili dosyaları | Gömülü compiler sürümü, modüller, replacement'lar ve build ayarları | Yerleşik statik ELF/PE/thin Mach-O incelemesi; Go kurulumu gerekmez |
|
||||
| Rust ikili dosyaları | Gömülü cargo-auditable crate adları, sürümleri, kaynakları ve bağımlılık ilişkileri | Yerleşik statik ELF/PE/thin Mach-O incelemesi; [Rust ikili dosyaları](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| WASM artefaktı | Doğrulama, bölümler, tam import/export WAT biçimleri ve decode edilmiş WAT | Çağıranın sağladığı WABT 1.0.42; `inspect_wasm_artifact` |
|
||||
| EVM bayt kodu | Yönlendirme seçicileri, bayt ofsetleri, çıkarımla belirlenen argümanlar ve durum değiştirilebilirliği | Linux x64 üzerinde yerel ham bayt/onaltılık girdi; [çevrimdışı EVM rehberi](../evm-bytecode.md) |
|
||||
| SQLite veritabanları | Tablolar, sütunlar, index'ler, view'lar, trigger'lar ve seçilen sıradan tablo satırları | Yerel database/WAL snapshot'ı; native SQLite sınırlarıyla Node.js 24.x >=24.15 veya 26+ |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · **Українська** · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: Реверс-інжиніринг будь-чого
|
||||
|
||||
@@ -137,14 +137,17 @@ npx rea-agents@latest setup
|
||||
|
||||
## Що можна аналізувати
|
||||
|
||||
REA потребує Node.js 22.x (>=22.19), 24.x (>=24.11) або 26+, а також npm. Додаткові інструменти й підтримувані системи залежать від цілі:
|
||||
REA потребує Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) або 26+ (>=26.12.1), а також npm. Додаткові інструменти й підтримувані системи залежать від цілі:
|
||||
|
||||
| Ціль | Що повертає REA | Вимоги й посібник |
|
||||
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Нативні бінарні файли | Псевдокод, асемблерний код, рядки, символи, виклики й посилання | Hopper, Ghidra або IDA; [нативний аналіз](../native-investigation.md) |
|
||||
| Структура ELF без запуску | Секції, сегменти, початкові символи/релокації та можливі захисні механізми за даними статичного аналізу | pwntools, наданий стороною, що викликає інструмент, у Linux x64; [діагностика бінарних файлів](../binary-diagnostics.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| Байт-код EVM | Селектори диспетчеризації, зміщення байтів, виведені припущення про аргументи та змінюваність стану | Локальні необроблені байти або шістнадцяткове представлення у Linux x64; [посібник EVM без запуску](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| Записані аварійні завершення в Linux | Необроблені записи note, регістри/сигнали кожного записаного потоку й необов'язкові кандидати зіставлення пам'яті | pwntools, наданий стороною, що викликає інструмент, у Linux x64; необов'язкові GDB/pwndbg; [записані аварійні завершення](../recorded-crashes.md) |
|
||||
| Встановлені настільні програми | Можливі середовища виконання, файли доказів, компоненти та наступні кроки | Обмежена перевірка каталогів і заголовків;[Настільні програми](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Модулі, імпорти, карти вихідного коду, маршрути, IPC і зв'язки з нативними доповненнями | Node.js і npm; [аналіз застосунків](../javascript-application-workflows.md) |
|
||||
|
||||
@@ -0,0 +1,435 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · **Roman Urdu**
|
||||
|
||||
# REA: Reverse Engineer Anything
|
||||
|
||||
### Binaries, applications aur runtime behavior ki reverse engineering ke liye ek MCP.
|
||||
|
||||
**Koi feature pasand aaya? Samjhein ke woh kaise kaam karta hai, binary level tak.**
|
||||
|
||||
[](https://www.npmjs.com/package/rea-agents)
|
||||
[](../mcp-contracts.md#generated-catalog)
|
||||
[](#kya-kuch-analyze-kar-sakte-hain)
|
||||
[](https://skills.sh/morluto/rea/reverse-engineer-anything)
|
||||
[](../../LICENSE)
|
||||
[](https://discord.gg/GkcryMnJDM)
|
||||
|
||||
<a href="https://trendshift.io/repositories/82054?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-82054" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/82054" alt="morluto%2Frea | Trendshift" width="250" height="55"/></a>
|
||||
|
||||
**[Website](https://rea.tools/) · [Guides](https://rea.tools/guides/) · [Showcases](https://rea.tools/showcase/)**
|
||||
|
||||
[Jaldi shuru karein](#jaldi-shuru-karein) · [REA kaise kaam karta hai](#rea-kaise-kaam-karta-hai) · [Kya kuch analyze kar sakte hain](#kya-kuch-analyze-kar-sakte-hain) · [Amli misaalein](#amli-misaalein) · [FAQ](#faq) · [Documentation](#documentation)
|
||||
|
||||
<code>npx rea-agents setup</code>
|
||||
|
||||
</div>
|
||||
|
||||
> [!IMPORTANT]
|
||||
> REA [morluto/rea](https://github.com/morluto/rea),
|
||||
> [rea.tools](https://rea.tools/) ya [rea-agents npm package](https://www.npmjs.com/package/rea-agents) se hasil karein.
|
||||
> Installation aur release ke links inhi official sources se kholein. Sirf milta-julta
|
||||
> repository naam ya copy kiya hua README kisi download ko official sabit nahi karta.
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<img src="../assets/rea-hopper-analysis.png" alt="REA ek native binary inspect karte hue Hopper ke andar apna analysis bridge shuru kar raha hai" width="1200" />
|
||||
|
||||
<br /><br />
|
||||
|
||||
<table aria-label="REA community">
|
||||
<tr>
|
||||
<td align="center" width="360">
|
||||
<a href="https://discord.gg/GkcryMnJDM">
|
||||
<img src="../assets/discord.svg" height="42" alt="Discord" /><br />
|
||||
<strong>Reverse Engineering Community mein shamil hon</strong>
|
||||
</a><br />
|
||||
<sub>Discord · Sawal jawab · Apna kaam dikhayein</sub>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
Kisi app mein aisa feature dekha jo aap apne product mein chahte hain? Apne agent se kahein ke REA ke zariye uski jaanch kare. Woh app ka source code mile baghair bhi use inspect kar sakta hai, feature kaam kaise karta hai samjha sakta hai, saboot dikha sakta hai aur aapke project ke liye uska ek version bana sakta hai.
|
||||
|
||||
REA aapke agent ko native binaries, JavaScript aur Electron apps, .NET assemblies aur websites inspect karne wale tools se jorta hai. Yehi tools terminal se bhi use kar sakte hain. Analysis local machine par hota hai, aur har natije ke saath uske saboot aur limitations bhi milti hain.
|
||||
|
||||
Setup REA ko aapke agent ke saath register karta hai aur uske mutabiq workflow instructions install karta hai. Native analysis ke liye pehle se installed Hopper, Ghidra ya IDA use ho sakta hai; aapki approval par setup Hopper bhi install kar sakta hai. Static JavaScript analysis ke liye native analysis engine ki zaroorat nahi.
|
||||
|
||||
> Setup instructions, tasveeron ke saath guides aur asli case studies ke liye **[REA ki website dekhein](https://rea.tools/)**.
|
||||
|
||||
## Jaldi shuru karein
|
||||
|
||||
Linux par Ghidra, JADX, firmware tools shuru karne aur static JavaScript/Electron
|
||||
analysis ke liye REA ke `PATH` par procps-compatible `ps` hona chahiye, taake
|
||||
process ownership check ho sake. Masla hal karne ke steps `docs/installation.md`
|
||||
ke "Linux owned-process prerequisite" section mein hain.
|
||||
|
||||
### Apna agent setup karein
|
||||
|
||||
Node.js aur npm installed hon to yeh command chalayein:
|
||||
|
||||
```bash
|
||||
npx rea-agents setup
|
||||
```
|
||||
|
||||
Apne agents select karein, proposed changes dekhein aur approve karein. Setup
|
||||
REA ka MCP server aur matching workflow instructions add karta hai, aur existing
|
||||
configuration ke backups banata hai. Iske baad apna agent restart karein.
|
||||
|
||||
Setup Claude Code, Codex, Cursor, Gemini CLI, Grok Build aur
|
||||
[doosre agents](../installation.md#supported-agents) support karta hai. Provider
|
||||
configuration aur manual MCP registration ke liye
|
||||
[installation aur setup](../installation.md) dekhein.
|
||||
|
||||
Context overhead kam rakhne ke liye MCP default mein compact input schemas use
|
||||
karta hai. Agar tamam advertised fields ki guidance aur nested validation details
|
||||
chahiye hon to apni MCP registration mein `REA_MCP_INPUT_SCHEMA_PROFILE=full`
|
||||
set karein. Dono profiles mein tamam tools aur canonical server validation
|
||||
maujood rehte hain. MCP contracts guide ka "Compact input schema profile"
|
||||
section dekhein.
|
||||
|
||||
### Apne agent se kahein
|
||||
|
||||
```text
|
||||
Samjho ke Notes app mein search kaise kaam karti hai, mujhe saboot dikhao aur
|
||||
mere project ke liye aisa hi feature banao.
|
||||
```
|
||||
|
||||
Notes ki jagah apni target app aur jis feature ko samajhna hai uska naam likhein.
|
||||
|
||||
### Terminal se use karein
|
||||
|
||||
Extract ki hui JavaScript/Electron app directory ya ASAR inspect karein:
|
||||
|
||||
```bash
|
||||
npx -y rea-agents@latest analyze-javascript-application /absolute/path/to/app --json
|
||||
```
|
||||
|
||||
Natije mein modules, imports, Electron boundaries aur unke saboot milte hain.
|
||||
Path ko apne target se badlein, jaise Windows par `"D:/apps/example"`.
|
||||
|
||||
Rozmarra use ke liye `rea` command install karne ke liye:
|
||||
|
||||
```bash
|
||||
npm install --global rea-agents
|
||||
rea --help
|
||||
```
|
||||
|
||||
Native analysis se pehle provider configure karein. Native commands, provider
|
||||
selection, snapshots aur scripting ke liye
|
||||
[CLI aur Evidence guide](../cli.md) dekhein.
|
||||
|
||||
### REA update karein
|
||||
|
||||
REA mein tezi se changes aate hain aur naye releases mein aksar bug fixes hoti
|
||||
hain. Apni installation updated rakhein.
|
||||
|
||||
Agar CLI `npm install --global` ya `bun add --global` se install ki hai:
|
||||
|
||||
```bash
|
||||
rea update
|
||||
```
|
||||
|
||||
`rea --update` isi verified workflow ka alias hai aur wohi global output flags
|
||||
accept karta hai. Doosre command controls ke saath use karte waqt `rea update`
|
||||
likhein.
|
||||
|
||||
Updater commands stdout aur stderr mila kar zyada se zyada 4 MiB retain karti
|
||||
hain. Command khatam hone ke baad is had se bade metadata replies reject ho
|
||||
jate hain; verbose installs bounded diagnostics ke saath jari rehti hain.
|
||||
Insaan ke liye progress output terminal ki backpressure ka khayal rakhta hai
|
||||
aur bheji hui writes mukammal hone ka intezar karta hai.
|
||||
|
||||
Bun global updates ke liye Bun 1.2.17 ya naya version chahiye. Purana Bun ho
|
||||
to `rea update` chalane se pehle Bun manually upgrade karein.
|
||||
|
||||
Agent registrations aur skill refresh karne ke liye update ke output mein
|
||||
di hui setup command chalayein.
|
||||
|
||||
Agar aap `npx` use karte hain to agent setup is tarah update karein:
|
||||
|
||||
```bash
|
||||
npx rea-agents@latest setup
|
||||
```
|
||||
|
||||
Setup changes review karein aur agent restart karein. Ek dafa chalane wali CLI
|
||||
commands ke liye `npx rea-agents@latest` ke baad command likhein. Bun ke saath
|
||||
`npx rea-agents@latest` ki jagah `bunx rea-agents@latest` use karein.
|
||||
|
||||
## REA kaise kaam karta hai
|
||||
|
||||
Aapka agent MCP ke zariye REA ko call karta hai, taake target inspect kare aur
|
||||
relevant code trace kare. REA apni findings saboot ke saath wapas deta hai.
|
||||
Agent unki bunyaad par agle sawal poochta hai, behavior samjhata hai ya
|
||||
implementation likh kar test karta hai. CLI commands bhi yehi workflows use
|
||||
karti hain.
|
||||
|
||||

|
||||
|
||||
[Puri size mein figure kholein](../../website/public/assets/figures/rea-investigation-flow.svg).
|
||||
|
||||
<a id="current-status"></a>
|
||||
|
||||
## Kya kuch analyze kar sakte hain
|
||||
|
||||
REA ke liye Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) ya 26.12.1+, aur npm chahiye.
|
||||
Mazeed tools aur host support target par depend karte hain:
|
||||
|
||||
| Target | REA kya wapas deta hai | Zarooriyat aur guide |
|
||||
| ----------------------- | ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Desktop installations | Runtime candidates, supporting files, component markers aur agle probes | Built-in bounded directory/header inspection; [desktop applications](../desktop-applications.md) |
|
||||
| Native binaries | Pseudocode, assembly, strings, symbols, calls aur references | Hopper, Ghidra ya IDA; [native analysis](../native-investigation.md) |
|
||||
| Offline ELF layout | Sections, segments, original symbols/relocations aur static mitigation candidates | Linux x64 par aapka diya hua pwntools; [binary diagnostics](../binary-diagnostics.md) |
|
||||
| Go binaries | Embedded compiler version, modules, replacements aur build settings | Built-in static ELF/PE/thin Mach-O inspection; Go install karna zaroori nahi |
|
||||
| GPU code objects | CUDA/HIP targets, selected kernel parameters aur resources, retained PTX text | Built-in static ELF/PE/fatbin/CUBIN/PTX inspection; [GPU code objects](../gpu-code-objects.md) |
|
||||
| Model artifacts | GGUF / safetensors metadata, tensor declarations aur unse nikale hue totals | Built-in header inspection; optional full-file hash; [model files](../model-artifacts.md) |
|
||||
| IL2CPP metadata | Unity global-metadata.dat assembly images, type aur method names aur index ranges | Versions 24, 27, 29, 31 aur 39 ki built-in static decoding; Unity zaroori nahi |
|
||||
| Godot PCK | Archive inventory aur extraction, original header/directory facts aur selected content identities | Built-in static formats 2, 3 aur 4; Godot zaroori nahi |
|
||||
| Rust binaries | Embedded cargo-auditable crate names, versions, sources aur dependency edges | Built-in static ELF/PE/thin Mach-O inspection; [Rust binaries](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries aur PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id aur ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, imports, lambdas aur Code header | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| WASM artifact | Validation, sections, exact import/export WAT forms aur decoded WAT | Aapka diya hua WABT 1.0.42; `inspect_wasm_artifact` |
|
||||
| EVM bytecode | Dispatch selectors, byte offsets, inferred arguments aur mutability | Linux x64 par local raw/hex carrier; [offline EVM guide](../evm-bytecode.md) |
|
||||
| SQLite databases | Tables, columns, indexes, views, triggers aur selected ordinary-table rows | Local database/WAL snapshot; native SQLite limits ke saath Node.js 24.x >=24.15 ya 26+ |
|
||||
| Recorded Linux crashes | Raw notes, har recorded thread ke registers/signals aur optional mapping candidates | Linux x64 par aapka diya hua pwntools; optional GDB/pwndbg; [recorded crashes](../recorded-crashes.md) |
|
||||
| JavaScript / Electron | Modules, imports, source maps, routes, IPC aur native add-on relationships | Node.js aur npm; Linux: procps-compatible `ps`; [application analysis](../javascript-application-workflows.md) |
|
||||
| Websites | Page structure, scripts, network observations aur requested screenshots | Chrome-family browser; [browser analysis](../browser-observation.md) |
|
||||
| Saved network captures | Requests, responses, exposed payloads aur source locations | HAR ya Fiddler Everywhere SAZ; native mitmproxy ke liye Linux par mitmdump; [capture guide](../web-network-captures.md) |
|
||||
| .NET assemblies | Metadata, CIL instructions, declared native dependencies aur build comparisons | Koi additional tool nahi (sirf static analysis); [managed-code guide](../managed-code-analysis.md) |
|
||||
| Android APKs | Manifest declarations, classes, decompiled methods aur references | Linux/macOS/Windows x64 par headless JADX aur full JDK; [Android guide](../android-analysis.md) |
|
||||
| APK signatures | v1/v2/v3/v3.1 signers, certificate fingerprints, key rotation aur digest self-consistency | Koi additional tool nahi (sirf static analysis); `inspect_apk_signature` |
|
||||
| Android devices | Devices, packages, processes, logs, dumps, screen captures aur APK/file transfers | Aapka diya hua adb (emulator ya hardware); [ADB guide](../adb-device-analysis.md) |
|
||||
| JEB projects | Engine-backed project units, artifact digests aur type/method pseudo-code | Aapka shuru kiya hua JEB client jo MCP serve kar raha ho, REA_JEB_MCP_URL se select karein; [JEB guide](../jeb-analysis.md) |
|
||||
| Android resources | Decoded manifest, string tables, locales aur version facts | Aapka diya hua Apktool launcher; [resource guide](../apktool-resource-analysis.md) |
|
||||
| Flutter apps | Dart snapshot hash, per-ABI library digests aur engine build provenance | Koi additional tool nahi (static APK parsing); [Flutter guide](../flutter-analysis.md) |
|
||||
| Firmware | Regions, extraction results aur native-analysis handoffs | Linux par Binwalk / Unblob; [firmware guide](../firmware-analysis.md) |
|
||||
| Recorded packets | Selected fields, repeated values, filters aur decode-as rules | Linux: TShark 4.x + prlimit; [capture guide](../packet-captures.md) |
|
||||
| Packet summaries | Endpoints, DNS, TLS SNI, protocol distribution aur HTTP requests | Aapke diye hue tshark aur capinfos (Linux par verified); [pcap guide](../pcap-analysis.md) |
|
||||
| Recorded logic signals | Decoder annotations, sample ranges aur diagnostics | Linux: sigrok-cli 0.7.2 + prlimit; [signal recordings](../signal-recordings.md) |
|
||||
| Packages aur resources | File inventories, digests, plists, Apple bundle structure aur extracted resources | [Artifact aur JavaScript guide](../javascript-artifact-reconstruction.md), [Apple applications](../apple-application-analysis.md) |
|
||||
| Process behavior | Terminal output, interactions, exit aur filesystem observations aur runs ka comparison | Native PTY ke saath Linux/macOS; [process capture](../process-capture.md) |
|
||||
| PyInstaller executables | CArchive members, Python version, entry scripts aur extracted bytecode | Koi additional tool nahi (sirf static analysis); [Python packaged applications](../python-packaged-applications.md) |
|
||||
|
||||
Static JavaScript aur .NET inspection di hui files ko application chalaye baghair
|
||||
parhti hai. Runtime capture aapki user permissions se selected target ko chalata
|
||||
hai ya uske saath interact karta hai; har runtime guide apne effects batati hai.
|
||||
|
||||
Offline native-binary inspection ke liye REA aapke diye hue GNU objdump aur
|
||||
Rizin bhi support karta hai. Provider setup, CLI commands aur Evidence ki
|
||||
limitations ke liye [reverse-engineering tools guide](../reverse-engineering-tools.md)
|
||||
dekhein. REA in dono providers ko install ya update nahi karta.
|
||||
|
||||
<a id="choosing-a-deep-analysis-provider"></a>
|
||||
|
||||
Native formats aur host support har provider ke liye alag ho sakte hain.
|
||||
[Hopper aur Ghidra setup](../installation.md#hopper),
|
||||
[IDA guide](../ida-provider.md) (optional native MCP bridge samet),
|
||||
[Kuna decompiler guide](../kuna-provider.md) aur
|
||||
[experimental Windows Ghidra support](../windows-ghidra-p0.md) dekhein.
|
||||
Ghidra [16-bit DOS analysis](../ghidra-dos.md) bhi support karta hai.
|
||||
Badi binaries ke liye `REA_GHIDRA_STARTUP_TIMEOUT_MS` ya
|
||||
`REA_HOPPER_STARTUP_TIMEOUT_MS` se provider ki startup deadline barhayein.
|
||||
Provider select karne ke liye [CLI guide](../cli.md#choose-a-provider) dekhein.
|
||||
Latest npm release ke baad add hone wale features ki
|
||||
[release availability](../installation.md#released-package-and-main) check karein.
|
||||
|
||||
## Amli misaalein
|
||||
|
||||
[](https://rea.tools/showcase/)
|
||||
|
||||
### DX-Ball: sound-pan calculation dobara banayein
|
||||
|
||||
Sound call se uske position-to-pan helper tak jayein, instructions inspect
|
||||
karein aur adhoore pseudocode ko C mein badlein. Dobara banaya gaya code 3,205
|
||||
original-x86 cases pass karta hai aur compiled function ke tamam 63 bytes
|
||||
dobara hasil karta hai.
|
||||
|
||||
[Case study parhein](https://rea.tools/showcase/dx-ball/) ·
|
||||
[Reconstruction repository](https://github.com/N0zoM1z0/dx-ball)
|
||||
|
||||
### Notion: Electron clipboard bridge trace karein
|
||||
|
||||
Renderer ki clipboard API dhoondein, preload aur IPC ke raste main process tak
|
||||
uska flow follow karein aur rich clipboard format inspect karein.
|
||||
|
||||
[Case study parhein](https://rea.tools/showcase/notion/)
|
||||
|
||||
### TH04: DOS bullet-ring calculation recover karein
|
||||
|
||||
Original PC-98 game ki 16-bit instructions inspect karein, fixed aur aimed angle
|
||||
calculations recover karein aur dobara banaye gaye C++ ko purane compiler ke
|
||||
output se compare karein.
|
||||
|
||||
[Case study parhein](https://rea.tools/showcase/th04/) ·
|
||||
[Reconstruction repository](https://github.com/N0zoM1z0/th04)
|
||||
|
||||
Agar aapne REA se koi dilchasp kaam kiya hai to hum dekhna chahenge. Apna case
|
||||
[issue](https://github.com/morluto/rea/issues) ya
|
||||
[pull request](https://github.com/morluto/rea/pulls) mein share karein. Target,
|
||||
apna sawal, REA ne kaise madad ki aur kya mila, yeh sab batayein.
|
||||
|
||||
## FAQ
|
||||
|
||||
<details>
|
||||
<summary><strong>Kaun se agents REA use kar sakte hain?</strong></summary>
|
||||
|
||||
Har woh agent jo local MCP servers support karta ho. Setup
|
||||
[supported agents](../installation.md#supported-agents) configure karta hai;
|
||||
doosre clients [manual MCP registration](../installation.md#mcp-registry)
|
||||
use kar sakte hain.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Kya mujhe Hopper, Ghidra ya IDA chahiye?</strong></summary>
|
||||
|
||||
Deep native analysis in mein se ek use karta hai. Static JavaScript aur .NET
|
||||
inspection native analysis engine ke baghair kaam karti hai. Approval ke baad
|
||||
setup Hopper install kar sakta hai; Ghidra aur IDA ke liye aapki existing
|
||||
installations use hoti hain. [Provider setup](../installation.md#hopper) dekhein.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Kya pehle Hopper shuru karna hoga?</strong></summary>
|
||||
|
||||
Jab kisi operation ko Hopper chahiye hota hai to REA use shuru karta hai.
|
||||
macOS par pehli dafa khulne wala dialog demo mode select karne ya license
|
||||
activate karne ko keh sakta hai. Pehle CLI/MCP operation ya unattended job se
|
||||
pehle usi user session mein yeh prompt complete karein. Zaroorat ho to Hopper
|
||||
manually kholein.
|
||||
[Hopper startup aur troubleshooting](../installation.md#launcher-paths-and-troubleshooting)
|
||||
dekhein.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>skills.sh se skill install karne se kya hota hai?</strong></summary>
|
||||
|
||||
Skill aapke agent ko jaanch karne ki instructions deti hai. REA ka MCP server
|
||||
register karne aur matching instructions install karne ke liye
|
||||
`npx rea-agents setup` use karein, phir agent restart karein.
|
||||
[Sirf skill ki installation](../installation.md#skill-only-installation) dekhein.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>REA kis tarah ka code wapas deta hai?</strong></summary>
|
||||
|
||||
Native analysis pseudocode aur assembly wapas deta hai. JavaScript/Electron
|
||||
analysis modules aur unke relationships recover karta hai. Aapka agent in
|
||||
findings se implementation likhta aur test karta hai;
|
||||
[amli misaalein](#amli-misaalein) iska tareeqa dikhati hain.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Kya REA meri app upload karta hai?</strong></summary>
|
||||
|
||||
REA targets ko local machine par analyze karta hai. Aapke agent ko tool results
|
||||
milte hain, aur uske model provider ki apni data policy hoti hai.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Bug mile to kya karun?</strong></summary>
|
||||
|
||||
Pehle update karein; ho sakta hai recent release mein masla hal ho chuka ho.
|
||||
|
||||
Agar CLI `npm install --global` ya `bun add --global` se install ki hai:
|
||||
|
||||
```bash
|
||||
rea update
|
||||
```
|
||||
|
||||
`npx` se agent setup ke liye:
|
||||
|
||||
```bash
|
||||
npx rea-agents@latest setup
|
||||
```
|
||||
|
||||
Agar agent use kar rahe hain to [setup refresh](#rea-update-karein) complete
|
||||
karke agent restart karein. Wohi task dobara try karein. Masla phir bhi ho to
|
||||
REA version, target type, reproduce karne ke steps aur error output ke saath
|
||||
[issue kholein](https://github.com/morluto/rea/issues).
|
||||
|
||||
</details>
|
||||
|
||||
## Documentation
|
||||
|
||||
Website ki [amli guides](https://rea.tools/guides/) se shuru karein.
|
||||
Exact options, prerequisites aur result contracts ke liye:
|
||||
|
||||
- [Installation aur setup](../installation.md): agent registration, provider configuration, updates aur uninstall.
|
||||
- [Readiness aur troubleshooting](../installation.md#check-readiness-for-your-task): ek agent ya analysis engine ka masla diagnose karein.
|
||||
- [CLI aur Evidence](../cli.md): commands, provider selection, snapshots, import/export aur exit statuses.
|
||||
- [MCP contracts](../mcp-contracts.md) aur [agent prompts](../mcp-prompts.md): tool results, sessions aur guided investigations.
|
||||
- [Tool catalog](../mcp-contracts.md#generated-catalog): tools, providers aur CLI commands ki generated inventory.
|
||||
- [Roadmap](../roadmap.md): planned work aur capability trackers.
|
||||
|
||||
Security vulnerabilities [SECURITY.md](../../SECURITY.md) ke zariye report karein.
|
||||
|
||||
## Stars ki history
|
||||
|
||||
🎉 **300,000 GitHub stars — shukriya!**
|
||||
|
||||
REA use karne, bugs report karne, features suggest karne, builds test karne aur
|
||||
fixes contribute karne wale sab logon ka shukriya.
|
||||
|
||||
<a href="https://www.star-history.com/?repos=morluto%2Frea&type=date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=morluto/rea&type=date&theme=dark&legend=top-left" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=morluto/rea&type=date" />
|
||||
<img alt="REA ke GitHub stars ki history" src="https://api.star-history.com/chart?repos=morluto/rea&type=date" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## Zimmedarana istemal
|
||||
|
||||
Responsible-use guidance ke liye [DISCLAIMER.md](../../DISCLAIMER.md) dekhein.
|
||||
|
||||
Ghair qanooni ya ghair ijazati istemal ke bare mein project ki position REA ke
|
||||
tamam versions, distribution channels aur platforms par lagu hoti hai; har copy
|
||||
par uske applicable licenses barqarar rehte hain.
|
||||
|
||||
REA qanooni research, taleem, interoperability, software preservation aur aise
|
||||
software ke analysis ke liye hai jo aapka apna ho ya jise examine karne ki aapko
|
||||
ijazat ho.
|
||||
|
||||
## Hissa dalein
|
||||
|
||||
REA mein aapki madad ka khairmaqdam hai! Bug report karne ya feature suggest
|
||||
karne ke liye [issue kholein](https://github.com/morluto/rea/issues), ya code aur
|
||||
docs behtar karne ke liye [pull request bhejein](https://github.com/morluto/rea/pulls).
|
||||
|
||||
Development setup aur checks ke liye [CONTRIBUTING.md](../../CONTRIBUTING.md),
|
||||
verification lanes ke liye [testing](../testing.md) aur project structure ke
|
||||
liye [architecture map](../architecture.mermaid) dekhein.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](../../LICENSE)
|
||||
|
||||
REA ka apna likha hua code MIT ke tehat licensed hai. Third-party material
|
||||
ke apne licenses aur copyright notices barqarar rehte hain. Dependency
|
||||
inventory, preserved license texts aur external tools ki terms ke liye
|
||||
[Third-party notices](../../THIRD_PARTY_NOTICES.md) dekhein.
|
||||
|
||||
IDA Pro / Hex-Rays decompilers, Hopper aur JEB samet **commercial tools qanooni
|
||||
tareeqe se hasil karna aur unke applicable licenses ke mutabiq use karne ki
|
||||
ijazat rakhna zaroori hai**. REA koi tool license, key ya activation ka haq
|
||||
nahi deta. Trials aur demos vendor ki terms ke tehat rehte hain, jin mein user,
|
||||
feature, automation aur output sharing ki pabandiyan bhi shamil hain. Cracked
|
||||
copies, chori ki hui keys, ghair ijazati key sharing aur license restrictions
|
||||
bypass karne ki ijazat nahi. Yeh guidance MIT ya third-party licenses ko
|
||||
tabdeel nahi karti.
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · **Tiếng Việt** · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA: Kỹ thuật dịch ngược cho mọi thứ
|
||||
|
||||
@@ -137,7 +137,7 @@ Tác nhân gọi REA qua MCP để kiểm tra mục tiêu và lần theo mã li
|
||||
|
||||
## Những gì bạn có thể phân tích
|
||||
|
||||
REA yêu cầu Node.js 22.x (>=22.19), 24.x (>=24.11) hoặc 26+, cùng với npm. Công cụ bổ sung và nền tảng chạy REA được hỗ trợ tùy thuộc vào mục tiêu:
|
||||
REA yêu cầu Node.js 22.x (>=22.23.4), 24.x (>=24.22.1) hoặc 26+ (>=26.12.1), cùng với npm. Công cụ bổ sung và nền tảng chạy REA được hỗ trợ tùy thuộc vào mục tiêu:
|
||||
|
||||
| Mục tiêu | REA trả về gì | Yêu cầu và hướng dẫn |
|
||||
| --------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -145,6 +145,9 @@ REA yêu cầu Node.js 22.x (>=22.19), 24.x (>=24.11) hoặc 26+, cùng với np
|
||||
| Bố cục ELF ngoại tuyến | Các section, segment, ký hiệu/thông tin tái định vị gốc và các biện pháp giảm thiểu có thể có từ phân tích tĩnh | pwntools do bên gọi cung cấp trên Linux x64; [chẩn đoán tệp nhị phân](../binary-diagnostics.md) |
|
||||
| Bytecode EVM | Bộ chọn điều phối, độ lệch byte, tham số suy luận và khả năng thay đổi trạng thái | Đầu vào cục bộ chứa byte thô hoặc dạng thập lục phân trên Linux x64; [hướng dẫn EVM ngoại tuyến](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| Sự cố Linux đã ghi lại | Bản ghi note thô, thanh ghi/tín hiệu của mọi luồng được ghi lại và các ứng viên ánh xạ tùy chọn | pwntools do bên gọi cung cấp trên Linux x64; GDB/pwndbg tùy chọn; [sự cố đã ghi lại](../recorded-crashes.md) |
|
||||
| Thư mục cài đặt ứng dụng máy tính | Các runtime có khả năng được dùng, tệp bằng chứng, dấu hiệu thành phần và bước tiếp theo | Kiểm tra thư mục và phần đầu tệp có giới hạn;[Ứng dụng máy tính](../desktop-applications.md) |
|
||||
| JavaScript / Electron | Mô-đun, các khai báo import, source map, tuyến, IPC và quan hệ với tiện ích mở rộng mã máy | Node.js và npm; [phân tích ứng dụng](../javascript-application-workflows.md) |
|
||||
|
||||
+31
-28
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · [简体中文](README_zh.md) · **繁體中文** · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA:逆向一切
|
||||
|
||||
@@ -139,34 +139,37 @@ AI 代理通過 MCP 呼叫 REA,檢查目標並追蹤相關程式碼。REA 返
|
||||
|
||||
## 可以分析什麼
|
||||
|
||||
REA 需要 Node.js 22.x(>=22.19)、24.x(>=24.11)或 26+,以及 npm。額外工具和主機支援取決於分析目標:
|
||||
REA 需要 Node.js 22.x(>=22.23.4)、24.x(>=24.22.1)或 26+ (>=26.12.1),以及 npm。額外工具和主機支援取決於分析目標:
|
||||
|
||||
| 目標 | REA 返回的內容 | 要求與指南 |
|
||||
| --------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| 原生二進位檔案 | 偽程式碼、組合語言、字串、符號、呼叫和引用 | Hopper、Ghidra 或 IDA;[原生分析](../native-investigation.md) |
|
||||
| 離線 ELF 佈局 | 節、段、原始符號/重定位資訊及靜態防護機制候選項 | Linux x64 上由呼叫方提供的 pwntools;[二進位診斷](../binary-diagnostics.md) |
|
||||
| Go 二進位檔案 | 內嵌編譯器版本、模組、替換項和建置設定 | 內建靜態 ELF/PE/thin Mach-O 檢查;無需安裝 Go |
|
||||
| WASM 工件 | 驗證、節、精確的匯入/匯出 WAT 形式及解碼後的 WAT | 呼叫方提供的 WABT 1.0.42;`inspect_wasm_artifact` |
|
||||
| EVM 位元組碼 | 分派選擇器、位元組偏移、推斷的參數和狀態可變性 | Linux x64 上的本地原始位元組/十六進位輸入載體;[離線 EVM 指南](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| 已記錄的 Linux 崩潰 | 原始 note 記錄、每個已記錄執行緒的暫存器/訊號及可選的對映候選項 | Linux x64 上由呼叫方提供的 pwntools;可選的 GDB/pwndbg;[已記錄崩潰](../recorded-crashes.md) |
|
||||
| 桌面安裝目錄 | 執行階段候選、支持檔案、元件標記與後續操作 | 有界的目錄與檔頭檢查;[桌面應用](../desktop-applications.md) |
|
||||
| JavaScript / Electron | 模組、匯入、source map、路由、IPC 和原生附加元件關係 | Node.js 和 npm;[應用分析](../javascript-application-workflows.md) |
|
||||
| 網站 | 頁面結構、腳本、網路觀察結果和按請求獲取的螢幕擷取畫面 | Chrome 系瀏覽器;[瀏覽器分析](../browser-observation.md) |
|
||||
| 已保存的網路擷取 | 請求、回應、可訪問的酬載和來源位置 | HAR;原生 mitmproxy 擷取需要 Linux 上的 mitmdump;[擷取指南](../web-network-captures.md) |
|
||||
| 封包擷取 | 端點、DNS、TLS SNI、通訊協定分佈和 HTTP 請求 | 呼叫端提供的 tshark 和 capinfos;[pcap 指南](../pcap-analysis.md) |
|
||||
| .NET 程式集 | 中繼資料、CIL 指令、聲明的原生依賴和建置對比 | 靜態檢查;[托管程式碼指南](../managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Android APK | 清單聲明、類別、反編譯的方法和引用 | Linux/macOS/Windows x64 上的無界面 JADX 和完整 JDK;[Android 指南](../android-analysis.md) |
|
||||
| Android 裝置 | 裝置、套件、程序、日誌、傾印、螢幕擷取以及 APK/檔案傳輸 | 呼叫端提供的 adb(模擬器或實體裝置);[ADB 指南](../adb-device-analysis.md) |
|
||||
| JEB 專案 | 引擎支援的專案單元、成品摘要和型別/方法的虛擬碼 | 由呼叫端啟動、提供 MCP 的 JEB 用戶端,透過 REA_JEB_MCP_URL 選擇;[JEB 指南](../jeb-analysis.md) |
|
||||
| Android 資源 | 解碼後的清單、字串表、語系和版本資訊 | 呼叫端提供的 Apktool 啟動器;[資源指南](../apktool-resource-analysis.md) |
|
||||
| Flutter 應用 | Dart 快照雜湊、依 ABI 的程式庫雜湊及引擎建置來源 | 無(靜態 APK 解析);[Flutter 指南](../flutter-analysis.md) |
|
||||
| 韌體 | 區域、提取結果和轉交原生分析的內容 | Linux 上的 Binwalk / Unblob;[韌體指南](../firmware-analysis.md) |
|
||||
| 封包記錄 | 指定欄位、重複值、篩選條件與解碼規則 | Linux: TShark 4.x + prlimit; [封包分析指南](../packet-captures.md) |
|
||||
| 錄製的邏輯訊號 | 解碼註解、樣本範圍與診斷資訊 | Linux: sigrok-cli 0.7.2 + prlimit; [訊號記錄指南](../signal-recordings.md) |
|
||||
| 軟體包與資源 | 檔案清單、摘要、plist、Apple bundle 結構和提取的資源 | [製品與 JavaScript 指南](../javascript-artifact-reconstruction.md)、[Apple 應用](../apple-application-analysis.md) |
|
||||
| 處理程序行為 | 終端輸出、互動、退出和檔案系統觀察結果,以及執行對比 | 支援原生 PTY 的 Linux/macOS;[處理程序擷取](../process-capture.md) |
|
||||
| 目標 | REA 返回的內容 | 要求與指南 |
|
||||
| --------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| 原生二進位檔案 | 偽程式碼、組合語言、字串、符號、呼叫和引用 | Hopper、Ghidra 或 IDA;[原生分析](../native-investigation.md) |
|
||||
| 離線 ELF 佈局 | 節、段、原始符號/重定位資訊及靜態防護機制候選項 | Linux x64 上由呼叫方提供的 pwntools;[二進位診斷](../binary-diagnostics.md) |
|
||||
| Go 二進位檔案 | 內嵌編譯器版本、模組、替換項和建置設定 | 內建靜態 ELF/PE/thin Mach-O 檢查;無需安裝 Go |
|
||||
| WASM 工件 | 驗證、節、精確的匯入/匯出 WAT 形式及解碼後的 WAT | 呼叫方提供的 WABT 1.0.42;`inspect_wasm_artifact` |
|
||||
| EVM 位元組碼 | 分派選擇器、位元組偏移、推斷的參數和狀態可變性 | Linux x64 上的本地原始位元組/十六進位輸入載體;[離線 EVM 指南](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| 已記錄的 Linux 崩潰 | 原始 note 記錄、每個已記錄執行緒的暫存器/訊號及可選的對映候選項 | Linux x64 上由呼叫方提供的 pwntools;可選的 GDB/pwndbg;[已記錄崩潰](../recorded-crashes.md) |
|
||||
| 桌面安裝目錄 | 執行階段候選、支持檔案、元件標記與後續操作 | 有界的目錄與檔頭檢查;[桌面應用](../desktop-applications.md) |
|
||||
| JavaScript / Electron | 模組、匯入、source map、路由、IPC 和原生附加元件關係 | Node.js 和 npm;[應用分析](../javascript-application-workflows.md) |
|
||||
| 網站 | 頁面結構、腳本、網路觀察結果和按請求獲取的螢幕擷取畫面 | Chrome 系瀏覽器;[瀏覽器分析](../browser-observation.md) |
|
||||
| 已保存的網路擷取 | 請求、回應、可訪問的酬載和來源位置 | HAR;原生 mitmproxy 擷取需要 Linux 上的 mitmdump;[擷取指南](../web-network-captures.md) |
|
||||
| 封包擷取 | 端點、DNS、TLS SNI、通訊協定分佈和 HTTP 請求 | 呼叫端提供的 tshark 和 capinfos;[pcap 指南](../pcap-analysis.md) |
|
||||
| .NET 程式集 | 中繼資料、CIL 指令、聲明的原生依賴和建置對比 | 靜態檢查;[托管程式碼指南](../managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Android APK | 清單聲明、類別、反編譯的方法和引用 | Linux/macOS/Windows x64 上的無界面 JADX 和完整 JDK;[Android 指南](../android-analysis.md) |
|
||||
| Android 裝置 | 裝置、套件、程序、日誌、傾印、螢幕擷取以及 APK/檔案傳輸 | 呼叫端提供的 adb(模擬器或實體裝置);[ADB 指南](../adb-device-analysis.md) |
|
||||
| JEB 專案 | 引擎支援的專案單元、成品摘要和型別/方法的虛擬碼 | 由呼叫端啟動、提供 MCP 的 JEB 用戶端,透過 REA_JEB_MCP_URL 選擇;[JEB 指南](../jeb-analysis.md) |
|
||||
| Android 資源 | 解碼後的清單、字串表、語系和版本資訊 | 呼叫端提供的 Apktool 啟動器;[資源指南](../apktool-resource-analysis.md) |
|
||||
| Flutter 應用 | Dart 快照雜湊、依 ABI 的程式庫雜湊及引擎建置來源 | 無(靜態 APK 解析);[Flutter 指南](../flutter-analysis.md) |
|
||||
| 韌體 | 區域、提取結果和轉交原生分析的內容 | Linux 上的 Binwalk / Unblob;[韌體指南](../firmware-analysis.md) |
|
||||
| 封包記錄 | 指定欄位、重複值、篩選條件與解碼規則 | Linux: TShark 4.x + prlimit; [封包分析指南](../packet-captures.md) |
|
||||
| 錄製的邏輯訊號 | 解碼註解、樣本範圍與診斷資訊 | Linux: sigrok-cli 0.7.2 + prlimit; [訊號記錄指南](../signal-recordings.md) |
|
||||
| 軟體包與資源 | 檔案清單、摘要、plist、Apple bundle 結構和提取的資源 | [製品與 JavaScript 指南](../javascript-artifact-reconstruction.md)、[Apple 應用](../apple-application-analysis.md) |
|
||||
| 處理程序行為 | 終端輸出、互動、退出和檔案系統觀察結果,以及執行對比 | 支援原生 PTY 的 Linux/macOS;[處理程序擷取](../process-capture.md) |
|
||||
|
||||
靜態 JavaScript 和 .NET 檢查讀取提供的檔案,不執行應用。執行階段擷取會以你的使用者權限執行目標或與之互動;各執行階段指南說明瞭具體影響。
|
||||
|
||||
|
||||
+31
-28
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
[English](../../README.md) · **简体中文** · [繁體中文](README_zh-TW.md) · [日本語](README_ja.md) · [한국어](README_ko.md) · [Türkçe](README_tr.md) · [Русский](README_ru.md) · [Tiếng Việt](README_vi.md) · [ไทย](README_th.md) · [Deutsch](README_de.md) · [Español](README_es.md) · [Français](README_fr.md) · [Українська](README_uk.md) · [Polski](README_pl.md) · [Português (Brasil)](README_pt-BR.md) · [العربية](README_ar.md) · [فارسی](README_fa.md) · [Bahasa Indonesia](README_id.md) · [Italiano](README_it.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md)
|
||||
· [Ελληνικά](README_el.md) · [മലയാളം](README_ml.md) · [Roman Urdu](README_ur-Latn.md)
|
||||
|
||||
# REA:逆向一切
|
||||
|
||||
@@ -139,34 +139,37 @@ npx rea-agents@latest setup
|
||||
|
||||
## 可以分析什么
|
||||
|
||||
REA 需要 Node.js 22.x(>=22.19)、24.x(>=24.11)或 26+,以及 npm。额外工具和主机支持取决于分析目标:
|
||||
REA 需要 Node.js 22.x(>=22.23.4)、24.x(>=24.22.1)或 26+ (>=26.12.1),以及 npm。额外工具和主机支持取决于分析目标:
|
||||
|
||||
| 目标 | REA 返回的内容 | 要求与指南 |
|
||||
| --------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| 原生二进制文件 | 伪代码、汇编、字符串、符号、调用和引用 | Hopper、Ghidra 或 IDA;[原生分析](../native-investigation.md) |
|
||||
| 离线 ELF 布局 | 节、段、原始符号/重定位信息及静态防护机制候选项 | Linux x64 上由调用方提供的 pwntools;[二进制诊断](../binary-diagnostics.md) |
|
||||
| Go 二进制文件 | 内嵌编译器版本、模块、替换项和构建设置 | 内置静态 ELF/PE/thin Mach-O 检查;无需安装 Go |
|
||||
| WASM 工件 | 验证、节、精确的导入/导出 WAT 形式及解码后的 WAT | 调用方提供的 WABT 1.0.42;`inspect_wasm_artifact` |
|
||||
| EVM 字节码 | 分派选择器、字节偏移、推断的参数和状态可变性 | Linux x64 上的本地原始字节/十六进制输入载体;[离线 EVM 指南](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| 已记录的 Linux 崩溃 | 原始 note 记录、每个已记录线程的寄存器/信号及可选的映射候选项 | Linux x64 上由调用方提供的 pwntools;可选的 GDB/pwndbg;[已记录崩溃](../recorded-crashes.md) |
|
||||
| 桌面安装目录 | 运行时候选、支持文件、组件标记和后续操作 | 有界的目录与文件头检查;[桌面应用](../desktop-applications.md) |
|
||||
| JavaScript / Electron | 模块、导入、source map、路由、IPC 和原生扩展关系 | Node.js 和 npm;[应用分析](../javascript-application-workflows.md) |
|
||||
| 网站 | 页面结构、脚本、网络观察结果和按请求获取的截图 | Chrome 系浏览器;[浏览器分析](../browser-observation.md) |
|
||||
| 已保存的网络捕获 | 请求、响应、可访问的载荷和来源位置 | HAR;原生 mitmproxy 捕获需要 Linux 上的 mitmdump;[捕获指南](../web-network-captures.md) |
|
||||
| 数据包捕获 | 端点、DNS、TLS SNI、协议分布和 HTTP 请求 | 调用方提供的 tshark 和 capinfos;[pcap 指南](../pcap-analysis.md) |
|
||||
| .NET 程序集 | 元数据、CIL 指令、声明的原生依赖和构建对比 | 静态检查;[托管代码指南](../managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Android APK | 清单声明、类、反编译的方法和引用 | Linux/macOS/Windows x64 上的无界面 JADX 和完整 JDK;[Android 指南](../android-analysis.md) |
|
||||
| Android 设备 | 设备、软件包、进程、日志、转储、屏幕截图以及 APK/文件传输 | 调用方提供的 adb(模拟器或实体设备);[ADB 指南](../adb-device-analysis.md) |
|
||||
| JEB 项目 | 引擎支持的项目单元、工件摘要和类型/方法的伪代码 | 由调用方启动、提供 MCP 的 JEB 客户端,通过 REA_JEB_MCP_URL 选择;[JEB 指南](../jeb-analysis.md) |
|
||||
| Android 资源 | 解码后的清单、字符串表、语言区域和版本信息 | 调用方提供的 Apktool 启动器;[资源指南](../apktool-resource-analysis.md) |
|
||||
| Flutter 应用 | Dart 快照哈希、按 ABI 的库摘要及引擎构建溯源 | 无(静态 APK 解析);[Flutter 指南](../flutter-analysis.md) |
|
||||
| 固件 | 区域、提取结果和转交原生分析的内容 | Linux 上的 Binwalk / Unblob;[固件指南](../firmware-analysis.md) |
|
||||
| 抓包文件 | 指定字段、重复值、过滤条件与解码规则 | Linux: TShark 4.x + prlimit; [抓包分析指南](../packet-captures.md) |
|
||||
| 录制的逻辑信号 | 解码注释、样本范围和诊断信息 | Linux: sigrok-cli 0.7.2 + prlimit; [信号记录指南](../signal-recordings.md) |
|
||||
| 软件包与资源 | 文件清单、摘要、plist、Apple bundle 结构和提取的资源 | [制品与 JavaScript 指南](../javascript-artifact-reconstruction.md)、[Apple 应用](../apple-application-analysis.md) |
|
||||
| 进程行为 | 终端输出、交互、退出和文件系统观察结果,以及运行对比 | 支持原生 PTY 的 Linux/macOS;[进程捕获](../process-capture.md) |
|
||||
| 目标 | REA 返回的内容 | 要求与指南 |
|
||||
| --------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| 原生二进制文件 | 伪代码、汇编、字符串、符号、调用和引用 | Hopper、Ghidra 或 IDA;[原生分析](../native-investigation.md) |
|
||||
| 离线 ELF 布局 | 节、段、原始符号/重定位信息及静态防护机制候选项 | Linux x64 上由调用方提供的 pwntools;[二进制诊断](../binary-diagnostics.md) |
|
||||
| Go 二进制文件 | 内嵌编译器版本、模块、替换项和构建设置 | 内置静态 ELF/PE/thin Mach-O 检查;无需安装 Go |
|
||||
| WASM 工件 | 验证、节、精确的导入/导出 WAT 形式及解码后的 WAT | 调用方提供的 WABT 1.0.42;`inspect_wasm_artifact` |
|
||||
| EVM 字节码 | 分派选择器、字节偏移、推断的参数和状态可变性 | Linux x64 上的本地原始字节/十六进制输入载体;[离线 EVM 指南](../evm-bytecode.md) |
|
||||
| Rust binaries | Embedded cargo-auditable dependency list | [Rust binaries](../rust-binaries.md) |
|
||||
| Erlang BEAM | IFF chunks, atoms, exports, and tables | Built-in static BEAM inspection; [Erlang BEAM](../erlang-beam.md) |
|
||||
| PE certificates | Authenticode WIN_CERTIFICATE entries and PKCS#7 signer/X.509 identity fields | Built-in static PE inspection; [PE certificates](../pe-certificates.md) |
|
||||
| ELF notes | PT_NOTE/SHT_NOTE owners, types, GNU build-id and ABI-tag fields | Built-in static ELF inspection; [ELF notes](../elf-notes.md) |
|
||||
| 已记录的 Linux 崩溃 | 原始 note 记录、每个已记录线程的寄存器/信号及可选的映射候选项 | Linux x64 上由调用方提供的 pwntools;可选的 GDB/pwndbg;[已记录崩溃](../recorded-crashes.md) |
|
||||
| 桌面安装目录 | 运行时候选、支持文件、组件标记和后续操作 | 有界的目录与文件头检查;[桌面应用](../desktop-applications.md) |
|
||||
| JavaScript / Electron | 模块、导入、source map、路由、IPC 和原生扩展关系 | Node.js 和 npm;[应用分析](../javascript-application-workflows.md) |
|
||||
| 网站 | 页面结构、脚本、网络观察结果和按请求获取的截图 | Chrome 系浏览器;[浏览器分析](../browser-observation.md) |
|
||||
| 已保存的网络捕获 | 请求、响应、可访问的载荷和来源位置 | HAR;原生 mitmproxy 捕获需要 Linux 上的 mitmdump;[捕获指南](../web-network-captures.md) |
|
||||
| 数据包捕获 | 端点、DNS、TLS SNI、协议分布和 HTTP 请求 | 调用方提供的 tshark 和 capinfos;[pcap 指南](../pcap-analysis.md) |
|
||||
| .NET 程序集 | 元数据、CIL 指令、声明的原生依赖和构建对比 | 静态检查;[托管代码指南](../managed-code-analysis.md) |
|
||||
| PyInstaller | CArchive, PYZ, Python bytecode | Static inspection; [Python packaged applications](../python-packaged-applications.md) |
|
||||
| Android APK | 清单声明、类、反编译的方法和引用 | Linux/macOS/Windows x64 上的无界面 JADX 和完整 JDK;[Android 指南](../android-analysis.md) |
|
||||
| Android 设备 | 设备、软件包、进程、日志、转储、屏幕截图以及 APK/文件传输 | 调用方提供的 adb(模拟器或实体设备);[ADB 指南](../adb-device-analysis.md) |
|
||||
| JEB 项目 | 引擎支持的项目单元、工件摘要和类型/方法的伪代码 | 由调用方启动、提供 MCP 的 JEB 客户端,通过 REA_JEB_MCP_URL 选择;[JEB 指南](../jeb-analysis.md) |
|
||||
| Android 资源 | 解码后的清单、字符串表、语言区域和版本信息 | 调用方提供的 Apktool 启动器;[资源指南](../apktool-resource-analysis.md) |
|
||||
| Flutter 应用 | Dart 快照哈希、按 ABI 的库摘要及引擎构建溯源 | 无(静态 APK 解析);[Flutter 指南](../flutter-analysis.md) |
|
||||
| 固件 | 区域、提取结果和转交原生分析的内容 | Linux 上的 Binwalk / Unblob;[固件指南](../firmware-analysis.md) |
|
||||
| 抓包文件 | 指定字段、重复值、过滤条件与解码规则 | Linux: TShark 4.x + prlimit; [抓包分析指南](../packet-captures.md) |
|
||||
| 录制的逻辑信号 | 解码注释、样本范围和诊断信息 | Linux: sigrok-cli 0.7.2 + prlimit; [信号记录指南](../signal-recordings.md) |
|
||||
| 软件包与资源 | 文件清单、摘要、plist、Apple bundle 结构和提取的资源 | [制品与 JavaScript 指南](../javascript-artifact-reconstruction.md)、[Apple 应用](../apple-application-analysis.md) |
|
||||
| 进程行为 | 终端输出、交互、退出和文件系统观察结果,以及运行对比 | 支持原生 PTY 的 Linux/macOS;[进程捕获](../process-capture.md) |
|
||||
|
||||
静态 JavaScript 和 .NET 检查读取提供的文件,不运行应用。运行时捕获会以你的用户权限运行目标或与之交互;各运行时指南说明了具体影响。
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@ input Evidence bundle. Contradictions, duplicate definitions or owners,
|
||||
residual unknowns, missing dependencies, and unavailable authority keep closure
|
||||
open or failed.
|
||||
|
||||
Every fixture and verifier proof must bind its outcome to the exact owner
|
||||
implementation digest and obligation revision being evaluated. See
|
||||
[proof applicability](#proof-applicability) for the caller-produced contract.
|
||||
|
||||
## Complete CLI request
|
||||
|
||||
This empty request is useful for checking client integration. It is valid and
|
||||
@@ -225,11 +229,18 @@ sample Evidence ID with an authenticated review record already present in
|
||||
|
||||
## Manifest and closure
|
||||
|
||||
A manifest binding names one owner and its exact implementation digest. Both
|
||||
A manifest binding names one owner and a caller-supplied `owner_sha256`. Both
|
||||
`original_cases` and the reconstruction fixture list must cover every
|
||||
`required_case_kinds` value with authenticated, comparable Evidence.
|
||||
`parser_type` is mandatory when `requires_parser_type` is true.
|
||||
|
||||
The ledger does not read `module_path`, execute `verifier.command`, or compute
|
||||
the implementation digest. The owner fields do not specify whether the digest
|
||||
covers module bytes, a symbol representation, or a multi-file implementation.
|
||||
The proof producer must document the exact hashed inputs and any canonicalization
|
||||
so another verifier can reproduce that commitment; a path or symbol name alone
|
||||
does not define it.
|
||||
|
||||
```json
|
||||
{
|
||||
"obligation_id": "protocol.rpc.cancel",
|
||||
@@ -315,10 +326,79 @@ A manifest binding names one owner and its exact implementation digest. Both
|
||||
}
|
||||
```
|
||||
|
||||
All referenced Evidence IDs must exist in the bundle. A green unit test cannot
|
||||
close a `packaged-process` obligation. A static-only source cannot close a
|
||||
runtime or process claim. Marking a claim `blocked` or `out-of-scope` records the
|
||||
disposition but does not silently count it as verified.
|
||||
A ready ledger requires every retained Evidence reference to resolve in the
|
||||
bundle, including references on optional case kinds. Unresolved references stay
|
||||
visible in the ledger and produce diagnostics; they cannot close the obligation.
|
||||
A green unit test cannot close a `packaged-process` obligation. A static-only
|
||||
source cannot close a runtime or process claim. Marking a claim `blocked` or
|
||||
`out-of-scope` records the disposition but does not silently count it as verified.
|
||||
|
||||
### Proof applicability
|
||||
|
||||
Keep three checks separate:
|
||||
|
||||
- **Authenticity:** the retained Evidence passes its integrity checks.
|
||||
- **Authority:** the observation has the kind and strength required by the claim.
|
||||
- **Applicability:** the proof describes the implementation and obligation
|
||||
revision currently being evaluated.
|
||||
|
||||
Proof producers supply observed Evidence with predicate type
|
||||
`rea.reconstruction-proof`, operation `verify_reconstruction_obligations`, and
|
||||
the following `normalized_result` shape, defined by
|
||||
`reconstructionObligationProofSchema`. REA evaluates retained results; this
|
||||
operation label does not expose a proof executor or run the manifest command.
|
||||
|
||||
```json
|
||||
{
|
||||
"bindings": [
|
||||
{
|
||||
"obligation_id": "protocol.rpc.cancel",
|
||||
"obligation_version": 1,
|
||||
"owner_sha256": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fixtures": [
|
||||
{
|
||||
"fixture_id": "fixture.cancel.positive",
|
||||
"case_kind": "positive",
|
||||
"passed": true
|
||||
}
|
||||
],
|
||||
"verifiers": [
|
||||
{
|
||||
"verifier_id": "verifier.cancel",
|
||||
"claim_id": "claim.cancel",
|
||||
"passed": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`owner_sha256` is the same lowercase 64-hex SHA-256 commitment supplied by the
|
||||
implementation owner in the manifest. The proof producer computes it from the
|
||||
same documented inputs and canonicalization described above; REA compares the
|
||||
commitments and does not recompute them. The proof's `obligation_version` must
|
||||
exactly equal the evaluated obligation version, including for generated
|
||||
obligations. Increase that version when revising a reviewed requirement.
|
||||
|
||||
Within one matching obligation/owner/revision binding, fixture proof must name
|
||||
the exact `(fixture_id, case_kind)` pair, and verifier proof the exact
|
||||
`(verifier_id, claim_id)` pair. Every selected claim must report `passed: true`;
|
||||
a matching failed claim cannot be hidden by a duplicate passing claim.
|
||||
Claims may share a record, but identities or outcomes from different bindings
|
||||
are never joined. Fixture and verifier Evidence authority must also satisfy the
|
||||
existing authority requirements.
|
||||
|
||||
Changing the owner digest or obligation version makes retained proof
|
||||
inapplicable. Missing identity, including legacy ID-array proof records, keeps
|
||||
the ledger open with `inapplicable-fixture-proof` or
|
||||
`inapplicable-verifier-proof`; details distinguish malformed or missing metadata
|
||||
(`invalid-proof`), `owner-mismatch`, `revision-mismatch`, and `claim-mismatch`.
|
||||
An applicable false outcome produces `fixture-failed` or `verifier-failed` and
|
||||
a failed required ledger. An unknown, unsupported, or skipped verifier declaration
|
||||
produces `verifier-unavailable` and keeps closure open. Replace fixture and
|
||||
verifier Evidence after implementation or requirement changes. Old Evidence
|
||||
remains valid provenance and cannot establish current applicability.
|
||||
|
||||
The `summary` counts obligations. `by_status`, `by_application_layer`, and
|
||||
`by_source_state` place each obligation in exactly one bucket.
|
||||
@@ -329,7 +409,9 @@ obligation's `source_state` do not affect its authority bucket.
|
||||
|
||||
The tool returns every obligation inline. Its `ledger_id` and `closure_digest`
|
||||
identify the complete result, including summaries, reports, ownership and
|
||||
dependency graphs, Evidence links, and limitations.
|
||||
dependency graphs, Evidence links, and limitations. A new `closure_digest`
|
||||
identifies a changed ledger; it does not establish that a verifier ran again.
|
||||
Applicability is checked against the retained proof's explicit bindings.
|
||||
|
||||
For named boundaries with explicit verifier contracts and package-proof kinds,
|
||||
see [reconstruction coverage](reconstruction-coverage.md).
|
||||
+24
-5
@@ -15,8 +15,16 @@ permissions restores the retained tarball and verifier runtime. It installs
|
||||
that exact archive into an empty prefix, then exercises CLI help/discovery and
|
||||
the real stdio MCP catalog/session contract. Installation finishes before the
|
||||
protocol deadline begins, with dependency lifecycle scripts disabled. Only a
|
||||
successful rehearsal enables the job with npm publishing authority. Both jobs
|
||||
use the same release-input action; neither rebuilds or repacks the archive.
|
||||
successful rehearsal enables the job with npm publishing authority. The publisher
|
||||
downloads only
|
||||
the original qualified archive and manifest, validates their source/run/attempt,
|
||||
version, Node identity and streamed digest using Node built-ins, then invokes
|
||||
`npm publish --ignore-scripts` against the official registry. A shared built-in
|
||||
registry reader checks existing bytes and tags afresh on every publisher attempt,
|
||||
including retries after partial publication. It does not install
|
||||
application dependencies, restore verifier code or execute package canaries.
|
||||
Pinned Node/npm, Actions and the runner remain trusted toolchain inputs. Neither
|
||||
job rebuilds or repacks the archive.
|
||||
This rehearsal checks package consumption on the Linux release runner;
|
||||
qualification retains its broader native-host and real-provider checks.
|
||||
|
||||
@@ -25,10 +33,19 @@ An existing version must match the qualified tarball's SHA-512 and intended
|
||||
`latest`/`next` dist-tag before it can be reused. Publication never overwrites
|
||||
an existing version or silently changes a dist-tag. After publication, only
|
||||
confirmed registry absence is retried within the propagation window. Content
|
||||
or tag mismatches fail immediately. The post-publication verifier installs
|
||||
or tag mismatches fail immediately. A separate post-publication job with read-only
|
||||
repository/actions permissions verifies registry bytes and tags, then installs
|
||||
from npm and repeats the same CLI/MCP checks; it also exercises a real update
|
||||
from an older stable release. For a prerelease on `next`, that updater still
|
||||
targets stable `latest`, as the public update command does.
|
||||
targets stable `latest`, as the public update command does. MCP publication
|
||||
depends on that verification job succeeding. Rehearsal, publication and both
|
||||
registry-verification/publication jobs do not inherit remote-cache credentials.
|
||||
|
||||
Qualification records the parsed `latest`/`next` channel in manifest schema v2.
|
||||
Rehearsal validates its exact SemVer mapping; the minimal publisher consumes the
|
||||
qualified channel without a second version parser. Only read-only recovery
|
||||
accepts existing schema-v1 artifacts, preserving their original bytes and
|
||||
source/run identity. New publication requires schema v2.
|
||||
|
||||
The required reverse-tools lane runs fresh coverage and both mutation
|
||||
preflights. Complete mutation sweeps run separately on a schedule or manual
|
||||
@@ -50,7 +67,9 @@ gh workflow run release-recovery.yml --ref main \
|
||||
```
|
||||
|
||||
Select the existing version and its original automatic Release run. Recovery
|
||||
requires that run's successful exact-source CI gate and npm publish step. It
|
||||
requires that run's successful exact-source CI gate plus a successful npm write
|
||||
or registry-byte verification. It recognizes verification in either the older
|
||||
publisher job or the separate post-publication job. It
|
||||
uses the existing release tag, original qualified tarball and verifier runtime;
|
||||
expired or missing artifacts stop recovery. The archive's source, version,
|
||||
original run/attempt and Node version must match, and its SHA-512 must equal
|
||||
|
||||
@@ -35,6 +35,15 @@ Captured stdout and stderr are retained up to a 16 MiB combined limit; `output_t
|
||||
|
||||
Persistent GDB sessions, including the MCP workflow and one-shot `rea debug-with-gdb` CLI, are available only on Linux. REA verifies a live inferior's output descriptors through `/proc` before detaching it; it does not claim equivalent descriptor verification on macOS. Windows is also unsupported because owned Job Object cleanup can terminate debugger inferiors. On supported Linux hosts, `start_gdb_session`, `gdb_console`, `gdb_session_status`, and `close_gdb_session` manage a persistent GDB/MI session in MCP. The one-shot CLI requires a caller-selected durable TTY: `rea debug-with-gdb --inferior-tty /dev/pts/7 'file ./program'`. The TTY must remain available after GDB exits so a detached inferior can continue writing. MCP starts GDB with `--nx --quiet --interpreter=mi3`, retries initialization with MI2 if MI3 initialization returns an error and cleanup succeeds, waits for its prompt, and disables auto-loading. Pass optional `inferior_tty` to select the terminal that future inferior runs use; REA configures it before the session becomes ready and checks the exact value with GDB/MI. `gdb_session_status` reports the selected path, whether REA still considers the configuration verified, and whether invalid UTF-8 has been observed in MI bytes (`mi_invalid_utf8`) or stderr (`stderr_invalid_utf8`). Commands that can change the inferior TTY or redirect a run revoke that verification permanently for the session, so close retains GDB ownership if a live inferior remains. Closing a session with one live inferior and a verified TTY automatically detaches the target, which can resume execution; MCP clients receive destructive-operation annotations for this behavior. The console remains unrestricted and can run shell commands, change target state, access files, and use network in the REA process user's security context. Raw MI records and console/target/log streams are returned with Evidence; command output is retained up to 16 MiB and explicitly marked when truncated. GDB startup waits 10000 ms and each MI command waits 120000 ms. This release has no runtime override for those deadlines, the 16 MiB command output budget, session capacity, or the pending-command queue. `command_timeout_ms` does not change them.
|
||||
|
||||
`completion_status` describes completion of the selected console command, not
|
||||
termination of its inferior. After a `^running` result, REA queues a read-only
|
||||
`-gdb-show mi-async` query and waits for its tokenized reply before releasing the
|
||||
command's output collector. The ordered `records` include that query reply;
|
||||
`mi` retains the console command's result. An inferior `*stopped` event or an
|
||||
early compatibility prompt does not establish that an outer command file has
|
||||
finished. See GDB's [MI output syntax](https://sourceware.org/gdb/current/onlinedocs/gdb.html/GDB_002fMI-Output-Syntax.html)
|
||||
and [command-file semantics](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Command-Files.html).
|
||||
|
||||
Before a normal close, REA checks for live GDB thread groups. If one remains and a durable `inferior_tty` is verified, REA asks GDB to detach it and confirms the detach before stopping the debugger. Without that sink, select and apply a disposition to each inferior through `gdb_console` (for example, detach or kill as appropriate), then retry close. REA never infers target ownership from a PID or path. When the MCP server shuts down, REA terminates only its directly owned GDB process after confirming no inferior or a sink-backed detach; otherwise it retains the process and its output streams for retry.
|
||||
|
||||
```text
|
||||
@@ -70,13 +79,48 @@ Captured stdout and stderr are retained up to a 16 MiB combined limit; `output_t
|
||||
Cutter commands use the local REA Python bridge and authenticated loopback messages.
|
||||
The client and plugin must support the current v2 handshake; older peers are
|
||||
rejected before dispatch because they cannot preserve cross-caller recovery proof.
|
||||
The client checks the final encoded request against the bridge's 16 MiB frame
|
||||
limit before dispatch; an oversized command does not retain a cleanup owner.
|
||||
Each bridge request waits 25000 ms. Discovery admits at most 256 descriptor
|
||||
The client checks the final encoded request against
|
||||
`REA_BRIDGE_MAX_REQUEST_BYTES` before dispatch. The budget applies to request
|
||||
payload bytes and excludes the terminating LF. Unset, the ceiling is 16777216
|
||||
bytes (16 MiB). A decimal integer from 7464 to 536870887 is accepted. The floor
|
||||
fits the largest bounded symbol-name command inside an authenticated Cutter
|
||||
frame. A Cutter status keeps its session id, connection proof, and up to 64
|
||||
completion receipts when the frame is tight. The observed `current_file` is
|
||||
included when it fits. When it does not, the status reports that path as
|
||||
unknown, and the client does not reuse the descriptor path with the new
|
||||
generation. The maximum is one byte under Node's 536870888-character string ceiling
|
||||
so the framing LF still fits. The ceiling counts the encoded payload. A JSON
|
||||
escape is measured before serialization and is not divided into the maximum
|
||||
again. A structured Cutter reply is admitted when that encoded payload fits,
|
||||
including a dense array of numbers. Cutter hashes the HMAC prefix and the payload as separate updates, so
|
||||
an exact-limit frame does not build one preimage string. The plugin measures and signs the response
|
||||
from bounded JSON pieces, then writes the authenticated frame in 64 KiB chunks. The bridge searches only the newly read bytes for the framing LF. The client unescapes each socket chunk into one response string, checks the proof, and then parses that string. A fitting reply keeps
|
||||
the original output and does not retain the paged wire frame plus another concatenated copy. Zero, negative, non-decimal, and out-of-range
|
||||
values are `configuration_invalid` and do not fall back to the default. The
|
||||
bridge accepts that full payload size and rejects a larger payload while
|
||||
bounding the read. An incomplete frame is still `Incomplete bridge request
|
||||
frame`. An oversized command does not retain a cleanup owner. Hopper uses the
|
||||
same request payload budget. A Hopper request is serialized when it reaches
|
||||
the bridge, so one waiting behind Hopper's serial bridge does not retain
|
||||
another copy of the encoded frame. REA injects a caller-selected value into the
|
||||
Hopper bootstrap and the bridge also reads the process environment; an injected
|
||||
value wins. Cutter reads the environment that starts Cutter and publishes
|
||||
`max_request_bytes` on its session descriptor. A Hopper or Cutter process
|
||||
started out of band without the setting uses 16777216 bytes. The client
|
||||
compares that advertisement with its own ceiling before a discovery status probe and before sending a command. A different ceiling is a mismatch only after the hello proves that descriptor is a live authenticated bridge; a stale descriptor is ignored. That hello does not send a status request. Discovery fails if any such live ceiling differs, even when another live session matches. A hello that
|
||||
never sends its authenticated frame does not hold the bridge accept loop.
|
||||
At most 8 connection threads run. A further accept is closed, and a failure to start a thread closes that socket without stopping the listener. A status `completed_connection` is the longest prefix of accepted connections that have terminated. It does not treat an earlier connection as finished because a later status reached the command lock first. Scalar values in one Cutter reply are encoded in bounded batches.
|
||||
A command reply that does not fit keeps its completion state and document
|
||||
generation, and reports an oversized path as unknown. Cutter response frames use this same ceiling and
|
||||
also exclude the terminating LF. A command response the client discards because it exceeds that ceiling stays an unknown execution and sets `output_truncated`, so Evidence records the omitted output. Hopper response reads are unchanged.
|
||||
Each bridge request waits 25000 ms. The Cutter hello frame still must arrive
|
||||
within 1 second. The authenticated command frame is read with one second per
|
||||
mebibyte of `REA_BRIDGE_MAX_REQUEST_BYTES`, and that read never waits longer
|
||||
than the same 25000 ms. Discovery admits at most 256 descriptor
|
||||
candidates and reads and probes at most eight concurrently. A larger directory
|
||||
reports `bridge_directory_capacity_exceeded`. This release has no runtime
|
||||
override for the 25000 ms request deadline, the 16777216 byte frame, or the
|
||||
256-candidate discovery budget.
|
||||
override for the 25000 ms request deadline or the 256-candidate discovery
|
||||
budget. Those limits do not follow `REA_BRIDGE_MAX_REQUEST_BYTES`.
|
||||
|
||||
Terminal receipts are recovered before another command, including from a new CLI
|
||||
invocation. A signed status response also confirms completion of older bridge
|
||||
@@ -88,7 +132,11 @@ identify `cutter_command` and retain `status` in
|
||||
`details.diagnostics.auxiliary_operation`; malformed proof still blocks dispatch.
|
||||
Descriptor failures likewise retain the requesting operation through cleanup.
|
||||
Command admission reports typed cancellation and treats the caller's abort reason
|
||||
as opaque metadata, without inferring cleanup ownership from it.
|
||||
as opaque metadata, without inferring cleanup ownership from it. A generation
|
||||
mismatch is an input correction only when the authenticated reply confirms
|
||||
`not_started`. Missing or ambiguous execution state retains the command's
|
||||
completion uncertainty until terminal proof arrives, even if the reply names a
|
||||
generation error.
|
||||
|
||||
## Configuration and coverage
|
||||
|
||||
|
||||
+48
-14
@@ -82,38 +82,63 @@ runtime dependency coverage. A missing section remains unknown rather than an
|
||||
empty dependency set. Retained views describe the captured artifact digest;
|
||||
they do not assert that the current file or running application is unchanged.
|
||||
|
||||
ELF section names are resolved through the section-header string table.
|
||||
Zlib-compressed name tables are decoded within the native structural budget.
|
||||
If a name table uses unsupported compression, the result reports that
|
||||
limitation and leaves `.dep-v0` presence unknown rather than reporting the
|
||||
section absent.
|
||||
|
||||
The inline Evidence result contains the artifact path, SHA-256, byte length,
|
||||
container format, architecture, word size, and byte order. When a `.dep-v0`
|
||||
section is present, `auditable_metadata` contains:
|
||||
|
||||
- `section_name`, `.dep-v0` for ELF and PE or `__DATA,.dep-v0` for thin Mach-O;
|
||||
- `file_offset` and `section_bytes`, the exact file range of the compressed section;
|
||||
- `compressed_bytes` and `uncompressed_bytes`;
|
||||
- `section_name`, `.dep-v0` for ELF and PE or `__DATA,.dep-v0` for Mach-O;
|
||||
- `file_offset` and `section_bytes`, the exact file range of the dependency
|
||||
section in the selected artifact, including accepted PE file-alignment bytes;
|
||||
- `compressed_bytes`, the zlib stream length used for the inflate-ratio limit,
|
||||
and `uncompressed_bytes`;
|
||||
- `format_version`, the embedded integer, or `null` when the field is omitted;
|
||||
- `packages`, in the section's original order, with `name`, `version`, `source`,
|
||||
`kind`, `dependencies`, and `root`;
|
||||
`kind`, `dependencies`, `features`, and `root`;
|
||||
- `root_package_index`, the single package marked `root`, or `null` when none is marked;
|
||||
- `dependency_edges`, pairs of package indices in package-then-dependency order;
|
||||
- `cyclic_dependency_indices`, sorted unique indices that participate in a cycle.
|
||||
|
||||
An omitted `kind` stays `null`. The embedded format treats that omission as
|
||||
runtime, and that default is not stored in the section. An omitted dependency
|
||||
list is an empty array. An omitted `root` flag is false.
|
||||
list is an empty array. An omitted `features` field is `null`, because it does
|
||||
not establish whether features were empty or the producer did not record them;
|
||||
an explicit empty array establishes an empty list. An omitted `root` flag is
|
||||
false.
|
||||
Historical [cargo-auditable 0.4 package records](https://github.com/rust-secure-code/cargo-auditable/blob/v0.4.0/auditable-serde/src/lib.rs)
|
||||
may include the package `features` list; REA preserves those strings. That
|
||||
version omitted empty feature lists during serialization, while version 0.5
|
||||
removed the field entirely, as recorded in its
|
||||
[changelog](https://github.com/rust-secure-code/cargo-auditable/blob/v0.5.0/CHANGELOG.md).
|
||||
|
||||
`rustc_commit` is present only when a `/rustc/<40-hex>/` path is found in
|
||||
read-only data. Its `evidence_kind` is `inferred`. The hash is not a claim that
|
||||
that compiler produced the binary. Several distinct hashes leave a single
|
||||
commit unknown.
|
||||
read-only data. For ELF, read-only non-executable `PT_LOAD` file ranges are
|
||||
searched alongside read-only sections, so an optional missing section-header
|
||||
table does not remove this search source. Its `evidence_kind` is `inferred`.
|
||||
The hash is not a claim that that compiler produced the binary. Several
|
||||
distinct hashes leave a single commit unknown.
|
||||
|
||||
## Limits and failures
|
||||
|
||||
The selected file is limited to 256 MiB. A dependency section is limited to 1
|
||||
MiB compressed. Inflated JSON is limited to the smaller of 8 MiB and 64 times
|
||||
the compressed size. The complete report is limited to 8 MiB. Empty sections,
|
||||
truncated or trailing zlib bytes, invalid JSON, unknown fields, dependency
|
||||
The selected file is limited to 256 MiB. A dependency section's zlib stream is
|
||||
limited to 1 MiB compressed. Inflated JSON is limited to the smaller of 8 MiB
|
||||
and 64 times the compressed stream length. The complete report is limited to
|
||||
8 MiB. Empty sections,
|
||||
truncated streams, nonpadding bytes after a zlib stream, invalid JSON, duplicate
|
||||
object fields, unknown fields, dependency
|
||||
indices outside the package list, more than one root package, and compressed
|
||||
dependency sections are typed failures. A cycle is reported and is not walked.
|
||||
|
||||
For PE images with `VirtualSize` zero, the raw-size fallback can include file
|
||||
alignment bytes. REA excludes a zero suffix only when the raw section size is
|
||||
the zlib stream length rounded up to the declared `FileAlignment`; nonzero or
|
||||
oversized suffixes and truncated streams remain failures.
|
||||
|
||||
A missing section returns success with `auditable_metadata: null` and a
|
||||
limitation. Absence of `.dep-v0` does not mean the binary has no dependencies.
|
||||
Unknown embedded format revisions are retained in `format_version` and
|
||||
@@ -124,8 +149,17 @@ verified. An omitted revision remains `null` and follows revision 0 semantics.
|
||||
Embedded names and versions are file content. They do not authenticate the
|
||||
packages or the compiler.
|
||||
|
||||
Universal Mach-O containers are unsupported. Select a thin slice first. ELF,
|
||||
PE, and thin Mach-O are the supported containers.
|
||||
ELF, PE, thin Mach-O and one selected slice of a universal Mach-O are the
|
||||
supported containers.
|
||||
A universal (FAT) Mach-O needs `architecture` (`x86`, `x86_64`, `arm`
|
||||
or `arm64`; CLI `--architecture`). REA reads its own FAT table, without `lipo`,
|
||||
and validates the selected slice's range, alignment and Mach-O header CPU
|
||||
against the table. The result keeps the universal file as `artifact` (its
|
||||
SHA-256 and size), adds `selected_slice` with the slice offset, length, raw CPU
|
||||
type/subtype and the FAT table digest, and reports the section and rustc-path offsets as a
|
||||
file offset inside that slice. Without `architecture`, or when the file has no
|
||||
such slice or several, the request fails on `architecture` and lists the slices
|
||||
present. `architecture` on any other image is rejected rather than ignored.
|
||||
|
||||
Package and dependency counts are checked against the minimum required JSON
|
||||
representation before graph allocation or schema cloning. Oversized graphs
|
||||
|
||||
+39
-15
@@ -31,10 +31,23 @@ The corresponding MCP request is:
|
||||
|
||||
`decoders` uses sigrok's decoder stack and option/channel syntax. Channel names
|
||||
must match the recording; REA does not guess wiring, baud rate or protocol.
|
||||
Omitting `input_format` requests sigrok's autodetection. Omitting `annotations`
|
||||
Each selected decoder channel needs a target, for example `uart:rx=RX`; a bare
|
||||
channel key such as `uart:rx` is missing that target. When sigrok reports a
|
||||
missing or unknown selected channel target, REA returns `invalid_request` for
|
||||
`decoders` even if sigrok continues with fallback annotations and exits
|
||||
successfully. The diagnostic and any partial stdout remain in `captured_output`;
|
||||
unrelated producer warnings do not change request status.
|
||||
Omitting `input_format` requests sigrok's autodetection. REA uses an immutable
|
||||
private copy whose filename retains the selected recording's final suffix,
|
||||
including a dotfile basename such as `.csv`. Filename-based format detection
|
||||
receives that hint without exposing the
|
||||
caller's directory to sigrok. Omitting `annotations`
|
||||
retains every annotation class. Both omitted selections are recorded as null.
|
||||
See the [upstream manual](https://sigrok.org/wiki/Sigrok-cli) for formats,
|
||||
decoder stacking and annotation selectors. No arbitrary command flags are accepted.
|
||||
If sigrok reports an explicitly selected input format as unknown, REA returns
|
||||
`invalid_request` for `input_format`, retains the producer diagnostic, and
|
||||
advises correcting the format or omitting it for autodetection. See the
|
||||
[upstream manual](https://sigrok.org/wiki/Sigrok-cli) for formats, decoder
|
||||
stacking and annotation selectors. No arbitrary command flags are accepted.
|
||||
|
||||
Output defaults to 50 literal LF-separated lines. Use `line_offset` and
|
||||
`line_limit` for later pages, or MCP `line_limit: null` / CLI `--all_lines`
|
||||
@@ -56,12 +69,18 @@ The returned Evidence includes the input path/digest, exact selections, tool
|
||||
configured and resolved paths/digests, full version banner (including library versions), annotation text
|
||||
with sample-number ranges, and stderr. For example, `1104-1938 uart-1: 52`
|
||||
is producer display text over a sample range, not a timestamp or an independently
|
||||
verified protocol fact. Text is retained verbatim; it is not parsed as a lossless
|
||||
binary payload. Empty output does not establish absence of traffic. Warnings
|
||||
remain visible even when sigrok exits zero, including `tool.version_diagnostics`
|
||||
from the separate version probe. Post-run identity failures name the tool, limiter
|
||||
or private copy involved, rather than blaming the admitted source. Resource-signal
|
||||
failures retain the signal and effective limits without inferring its exact cause.
|
||||
verified protocol fact. Valid UTF-8 text is retained verbatim; it is not parsed as
|
||||
a lossless binary payload. If any sigrok stdout or stderr stream is invalid UTF-8,
|
||||
REA returns `unreadable_output` with the replacement-decoded text in
|
||||
`captured_output` and the affected streams in
|
||||
`details.diagnostics.invalid_utf8_streams`.
|
||||
It does not report that text as successful Evidence. A valid literal replacement
|
||||
character remains ordinary producer text. Empty output does not establish absence
|
||||
of traffic. Warnings remain visible even when sigrok exits zero, including
|
||||
`tool.version_diagnostics` from the separate version probe. Post-run identity
|
||||
failures name the tool, limiter or private copy involved, rather than blaming the
|
||||
admitted source. Resource-signal failures retain the signal and effective limits
|
||||
without inferring its exact cause.
|
||||
|
||||
REA decodes a private, read-only copy of the recording, verifies that copy and
|
||||
the selected executable and resource limiter after decoding, and removes the workspace after owned
|
||||
@@ -92,7 +111,8 @@ REA_SIGROK_COMMAND=/absolute/path/to/sigrok-cli node scripts/verify-signal-recor
|
||||
|
||||
The verifier synthesizes a 9600-baud 8N1 UART VCD carrying `REA`, then checks
|
||||
actual CLI/MCP parity, advertised schemas, stored Evidence, source hashes,
|
||||
annotation filtering/autodetection, invalid decoder/input failures and cleanup.
|
||||
annotation filtering/autodetection, invalid decoder/input failures, missing
|
||||
channel rejection with retained partial output, and cleanup.
|
||||
An optional positional REA entrypoint verifies an installed package.
|
||||
The real-tool lane requires Linux, sigrok-cli 0.7.2 and libsigrokdecode. A separate
|
||||
kernel-limit regression checks the inherited soft/hard limits and verifies an
|
||||
@@ -138,8 +158,12 @@ is copied so a retained page does not keep the complete producer output alive.
|
||||
Discovery shares decoding's owned process, admission slot, resource limits,
|
||||
cleanup retries and Evidence delivery. It records the executable and limiter
|
||||
identities, version banner and warnings. Failed version checks and malformed
|
||||
producer output preserve diagnostics. Help is producer text, not an independently
|
||||
validated parameter schema. Each request probes again; it does not cache or claim
|
||||
stable pages across installation changes. Libraries/decoder modules remain
|
||||
trusted and are not fully fingerprinted. Catalog output includes a SHA-256 of
|
||||
its executable, not a digest of the complete installation.
|
||||
producer output preserve diagnostics. Catalog names, help lines and version
|
||||
output follow decoding's UTF-8 handling: malformed streams produce an
|
||||
`unreadable_output` error with replacement-decoded captured text and the affected
|
||||
streams identified in `details.diagnostics.invalid_utf8_streams`. Help is
|
||||
producer text, not an independently validated parameter schema. Each request
|
||||
probes again; it does not cache or claim stable pages across installation
|
||||
changes. Libraries/decoder modules remain trusted and are not fully fingerprinted.
|
||||
Catalog output includes a SHA-256 of its executable, not a digest of the complete
|
||||
installation.
|
||||
@@ -36,7 +36,8 @@ previous increment.
|
||||
and `--name` must be a kebab-case label of at most 64 characters that is not a
|
||||
device name Windows reserves (`con`, `prn`, `aux`, `nul`, `com1`–`com9`,
|
||||
`lpt1`–`lpt9`), since the env folder could not be created there.
|
||||
- The Dockerfile reads `FROM node:24.18.0-bookworm-slim`, sets
|
||||
- The Dockerfile uses the Node version pinned in `.nvmrc` with the
|
||||
`bookworm-slim` variant, sets
|
||||
`MCP_HOST=0.0.0.0` and `MCP_PORT=18765`, installs Debian's `python3` for the
|
||||
framework's readiness probe, installs
|
||||
`rea-agents@<PRODUCT_IDENTITY.packageVersion>` from the registry or, with
|
||||
|
||||
@@ -59,7 +59,9 @@ later increment.
|
||||
`recorded_line_truncated`; an explicit empty query is `?`), `body_recorded` (false
|
||||
when the capture kept no response body, so a `null` body is not mistaken for
|
||||
a recorded one), `body_encoding` (`base64` when the retained bytes are not
|
||||
UTF-8, so they are returned exactly rather than decoded lossily) and
|
||||
UTF-8, so they are returned exactly rather than decoded lossily;
|
||||
`unsupported` with a null body and `body_recorded: true` when a declared HAR
|
||||
encoding cannot be decoded; the cited capture retains its original text and encoding) and
|
||||
`truncated` (a large retained base64 body is decoded only up to that limit),
|
||||
as both
|
||||
structured content and text, with REA's existing target-content provenance
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# Plan
|
||||
|
||||
1. Export the capture parser from `environmentSource.ts` so a probe loads like a capture.
|
||||
2. `environmentCompareMatch.ts`: a probe request to a tool and its arguments.
|
||||
3. `environmentCompareIds.ts`: the id map, natural-key pairing, learning from two answers, translating arguments.
|
||||
4. `environmentCompareDiff.ts`: normalisation and categorised differences.
|
||||
5. `environmentCompare.ts`: per probe, reset the state, answer each request, compare and learn; the report.
|
||||
6. `rea environment-compare` in `src/cli/environmentCommands.ts`, documented in `docs/agent-environments.md` and
|
||||
`docs/cli.md`.
|
||||
7. Tests: matching, pairing, normalisation and categories as unit tests; the command over a fixture capture and probes.
|
||||
8. Verification on VMs: six applications brought up and seeded as for their capture, reset from a snapshot per sequence,
|
||||
driven by a script that records each sequence as a HAR; baseline reports per environment.
|
||||
@@ -0,0 +1,92 @@
|
||||
# Compare an environment with the application it came from
|
||||
|
||||
Issue: https://github.com/morluto/rea/issues/4933
|
||||
|
||||
## Outcome
|
||||
|
||||
An environment is only as useful as it is faithful: an agent trained or graded on it should meet the behaviour of the
|
||||
application it was captured from. REA checks an environment only against its own capture, so nothing says how far it
|
||||
drifts from the application on calls the capture did not make, after writes, or on errors.
|
||||
|
||||
`rea environment-compare` measures that. It takes an environment (a manifest and its capture Evidence) and one or more
|
||||
**probe captures**, each a recording of one call sequence made against the live application, and reports how many of the
|
||||
probe's calls the environment answers as the application did, which tools disagree and how.
|
||||
|
||||
The command only reads Evidence: it makes no network call. Whoever records the probes drives the application with its own
|
||||
credentials and resets it between sequences.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Inputs: the manifest Evidence, its capture Evidence (`--evidence`), and one or more probe capture Evidence files
|
||||
(`--probe`, repeatable), each `inspect-web-network-capture` or `capture-browser-scenario` Evidence of one sequence.
|
||||
- Each probe is one sequence run against a freshly reset application. Before each probe the environment's state is reset,
|
||||
so sequences are independent on both sides.
|
||||
- Requests are taken in the probe's order (start time, then ordinal; ordinal alone when any record lacks a start
|
||||
time, as state extraction orders them). A request is matched to the manifest tool of the
|
||||
same method whose path template it fits with the most literal segments; format-rule parameters must fit their format
|
||||
once percent-decoded, as replay reads them.
|
||||
Query values the tool takes and a JSON body become the tool's arguments. A path argument is the raw segment: the
|
||||
environment decodes it once, so a segment encoded twice is not read as a second decoding. Replay matches that raw
|
||||
argument against a recorded segment that equals it, equals its one decoding, or decodes once to it.
|
||||
- A record without a usable request line (a redacted URL, a transaction the capture cannot attribute, an unparseable
|
||||
URL or no method) is not replayed, nor is a request to another origin than the probe's application (`other-origin`),
|
||||
which is the origin with the most JSON-like records, as the manifest chooses its own. A request with no recorded
|
||||
answer is made, since it may have changed the application, but not compared. Each is listed per probe with its
|
||||
reason and left out of agreement.
|
||||
- A request no tool matches is reported `no-tool`; a matched tool the environment does not offer, such as a write it
|
||||
withholds, is reported `not-served`. Neither is answered.
|
||||
- Ids differ between a re-seeded application and the capture. The comparison maps them:
|
||||
- seeded entities pair across the two answers by a natural key: a field present on every element of both arrays whose
|
||||
string values are unique on each side and shared between them;
|
||||
- identifier fields (`id`, `uuid`, `guid`, and names ending in `_id`, `Id`, `ID`, `_uuid` or `Uuid`) of paired objects,
|
||||
and of the two answers to the same call, map the live value to the environment's value; a create's two answers map
|
||||
the new ids, including a response that is only that id at the write plan's identity location. The `id`, `uuid` or
|
||||
`guid` of the answer's own entities (at the read view's entity or list location, a write's response location, or
|
||||
else the root) also maps within the collection the call names, since two collections can reuse a live id for
|
||||
different entities. An equal pair is kept in that collection, so another collection's mapping of the same live id
|
||||
does not replace it. Global mappings are one-to-one and first-pair-wins; equal global pairs also reserve both ids.
|
||||
If an equal pair conflicts with another pairing, its contested live or environment id is not used to normalize
|
||||
either pair, in either observation order. Only non-identity, unconflicted mappings count as mapped ids. Outside
|
||||
identifier fields, a string maps only at a field where learning found it held as an id in environment state. The
|
||||
keys of two objects keyed by ids map
|
||||
when their values pair (keys that partly overlap only when they are digits, UUIDs or their entries' identities, and
|
||||
every value pairs);
|
||||
- ids are learned only from an answer the environment gave this call, from its state or from a recording of exactly
|
||||
this call, its whole request line and its request body: a recording of another call that replay answers with
|
||||
instead holds other entities. A tool that takes a body does not match a recording whose body the probe did not send;
|
||||
- path, query and body values equal to a mapped live id are translated before the environment answers, a path
|
||||
parameter by the collection it names, except query values that page a list (`limit`, `offset`, `page` and the
|
||||
like), which count items rather than name one. A literal route segment is not translated. A nested collection is
|
||||
the live path's concrete parent values, each parameter decoded once, so two parents do not share one child map and
|
||||
spellings replay treats as equal name one. A second encoding stays a different parent. Learning and translation use
|
||||
that same live path.
|
||||
A path value the map does not know, and the environment's state does not hold, is reported `unmapped-id`.
|
||||
- A call is checked against the served tool's input schema first, as the MCP server checks it; a call it refuses is
|
||||
reported `refused`. A browser probe keeps its request bodies; one captured without response bodies is refused, since
|
||||
only statuses would compare, and so is one that makes POST, PUT or PATCH calls without recorded request bodies, since
|
||||
those calls would be made empty.
|
||||
- Answers compare after normalisation: empty response text and JSON `null` equal no body (a JSON empty string stays one);
|
||||
decoded JSON values compare structurally, plain text compares as text, and retained base64 bodies compare as bytes
|
||||
(including against UTF-8 text with the same bytes), without treating a base64 spelling as text. Mapped ids compare
|
||||
equal in identifier fields, in `ids`/`uuids`/`guids` scalar lists, and for an entity's own identity within the call's
|
||||
collection; other numeric fields stay literal. Any other id compares by the
|
||||
probe's mapping, and an entity's own identity both sides hold verbatim differs when its collection's mapping gives it
|
||||
another environment value (a reference keeps raw equality, as the probe's mapping cannot tell which collection it
|
||||
names); an object's members compare under the environment's mapped keys only when it is keyed by learned ids as
|
||||
learning reads one, and any other object compares field by field; two clock values (ISO-8601 strings, or epoch numbers under
|
||||
time-named fields) compare by format only; two different generated values (both UUIDs, or both of one length and the
|
||||
same character classes with a digit) that neither side maps compare equal and are counted. A body over the replay
|
||||
limit, text or binary, compares by status only, as does a live body the probe did not record, unless the answer has
|
||||
none by definition (204, 205, 304, or an answer to `HEAD`). Both are counted.
|
||||
- A step agrees when the statuses are equal and the normalised bodies are. Differences are categorised: `status`,
|
||||
`missing-field` (the application had it), `extra-field`, `value`, `length`, `order`, `clock-format`, `refused` (the
|
||||
environment refused the call), `not-served`, `no-tool` and `unmapped-id`, each with a JSON pointer and short values.
|
||||
- The report gives agreement overall, per probe and per tool, agreement ignoring item order beside it, the counts per
|
||||
category, the ids mapped and the values normalised, the records left uncompared, and each step's differences (at most
|
||||
20 per step).
|
||||
|
||||
## Non-goals
|
||||
|
||||
- No network access, no credentials, no reset of the application: probes are recorded outside REA.
|
||||
- No generation of call sequences; a later change generates them where the environment disagrees.
|
||||
- No change to how environments serve.
|
||||
@@ -0,0 +1,12 @@
|
||||
# Tasks
|
||||
|
||||
- [x] Record the outcome, requirements and non-goals.
|
||||
- [x] Load probes as captures.
|
||||
- [x] Match probe requests to tools.
|
||||
- [x] Map ids and translate arguments.
|
||||
- [x] Normalise and categorise differences.
|
||||
- [x] Compare per probe and report.
|
||||
- [x] Add the command and its documentation.
|
||||
- [x] Add unit and command tests.
|
||||
- [x] Run the gates.
|
||||
- [x] Measure six environments against their live applications and record the results.
|
||||
Loaded 100 of 2311 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user