reverse-engineering-assistant 1.0.1__tar.gz → 1.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/PKG-INFO +3 -1
  2. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/README.md +2 -0
  3. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/pyproject.toml +1 -1
  4. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant/api_server_tools/llm_tools.py +31 -3
  5. reverse-engineering-assistant-1.0.1/reverse_engineering_assistant/api_server_tools/function_tools.py → reverse-engineering-assistant-1.0.3/reverse_engineering_assistant/api_server_tools/re_tools.py +39 -5
  6. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant/assistant_api_server.py +2 -2
  7. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant/tool_protocol.py +55 -6
  8. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant.egg-info/PKG-INFO +3 -1
  9. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant.egg-info/SOURCES.txt +2 -2
  10. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant/__init__.py +0 -0
  11. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant/api_server_tools/__init__.py +0 -0
  12. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant/assistant.py +0 -0
  13. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant/configuration.py +0 -0
  14. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant/documents.py +0 -0
  15. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant/model.py +0 -0
  16. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant/reva_exceptions.py +0 -0
  17. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant/tool.py +0 -0
  18. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant.egg-info/dependency_links.txt +0 -0
  19. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant.egg-info/entry_points.txt +0 -0
  20. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant.egg-info/requires.txt +0 -0
  21. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/reverse_engineering_assistant.egg-info/top_level.txt +0 -0
  22. {reverse-engineering-assistant-1.0.1 → reverse-engineering-assistant-1.0.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reverse-engineering-assistant
3
- Version: 1.0.1
3
+ Version: 1.0.3
4
4
  Summary: An AI assistant for reverse engineering tasks
5
5
  Author: サイバーカイダ (cyberkaida)
6
6
  Classifier: License :: OSI Approved :: Apache Software License
@@ -145,6 +145,8 @@ revassistant --project ${NAME_OF_YOUR_PROJECT}
145
145
 
146
146
  ## Usage
147
147
 
148
+ The [ghidra-assistant](ghidra-assistant/README.md) plugin must be installed first.
149
+
148
150
  After installation, enable the `ReVaPlugin` extension in the CodeBrowser tool (Open a file and click: File -> Configure -> Miscellaneous).
149
151
 
150
152
  If you want ReVa enabled by default, click File -> Save Tool to save the configuration.
@@ -124,6 +124,8 @@ revassistant --project ${NAME_OF_YOUR_PROJECT}
124
124
 
125
125
  ## Usage
126
126
 
127
+ The [ghidra-assistant](ghidra-assistant/README.md) plugin must be installed first.
128
+
127
129
  After installation, enable the `ReVaPlugin` extension in the CodeBrowser tool (Open a file and click: File -> Configure -> Miscellaneous).
128
130
 
129
131
  If you want ReVa enabled by default, click File -> Save Tool to save the configuration.
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "reverse-engineering-assistant"
7
7
  readme = "README.md"
8
- version = "1.0.1"
8
+ version = "1.0.3"
9
9
  authors = [
10
10
  {name="サイバーカイダ (cyberkaida)"},
11
11
  ]
@@ -1,9 +1,18 @@
1
1
  from typing import Dict, List, Optional
2
2
  from ..assistant_api_server import register_message_handler, RevaMessageHandler, RevaCallbackHandler
3
- from ..tool_protocol import RevaGetNewVariableName, RevaGetNewVariableNameResponse, RevaGetNewSymbolName, RevaGetNewSymbolNameResponse
3
+ from ..tool_protocol import (
4
+ RevaExplain,
5
+ RevaGetNewVariableName,
6
+ RevaGetNewVariableNameResponse,
7
+ RevaGetNewSymbolName,
8
+ RevaGetNewSymbolNameResponse,
9
+ RevaExplain,
10
+ RevaExplainResponse,
11
+ RevaLocation,
12
+ )
4
13
 
5
14
  from ..reva_exceptions import RevaToolException
6
-
15
+ import threading
7
16
  import logging
8
17
 
9
18
 
@@ -36,4 +45,23 @@ class HandleGetNewSymbolName(RevaMessageHandler):
36
45
  # Block until ReVa finishes analysis.
37
46
  _ = self.assistant.query(question)
38
47
  response = RevaGetNewSymbolNameResponse(response_to=message.message_id)
39
- return response
48
+ return response
49
+
50
+ @register_message_handler
51
+ class HandleExplain(RevaMessageHandler):
52
+ handles_type = RevaExplain
53
+ def run(self, callback_handler: RevaCallbackHandler) -> RevaExplainResponse:
54
+ # Extract the content and ask the LLM what it thinks...
55
+ assert isinstance(callback_handler.message, RevaExplain)
56
+ message: RevaExplain = callback_handler.message
57
+ question = f"""
58
+ Explain the following location in detail, leave comments as needed.
59
+ """
60
+
61
+ location: RevaLocation = message.location
62
+
63
+ if message.location is not None:
64
+ question += f"\n{message.location}"
65
+ # Block until ReVa finishes analysis.
66
+ threading.Thread(target=self.assistant.query, args=(question,)).start()
67
+ return RevaExplainResponse(response_to=message.message_id)
@@ -91,13 +91,14 @@ class RevaDecompilationIndex(RevaRemoteTool):
91
91
  # Now we can ask the tool
92
92
  get_decompilation_message = RevaGetDecompilation(address=address, function=name)
93
93
  response = self.submit_to_tool(get_decompilation_message)
94
- assert isinstance(response, RevaMessageResponse), "Incorrect type returned from callback handler."
95
-
96
94
  if response.error_message:
97
95
  raise RevaToolException(response.error_message)
96
+ assert isinstance(response, RevaMessageResponse), "Incorrect type returned from callback handler."
97
+
98
+
98
99
 
99
100
  if not isinstance(response, RevaGetDecompilationResponse):
100
- raise ValueError(f"Expected a RevaGetDecompilationResponse, got {response}")
101
+ raise RevaToolException(f"Expected a RevaGetDecompilationResponse, got {response}")
101
102
 
102
103
  respose: RevaGetDecompilationResponse = response
103
104
 
@@ -107,6 +108,7 @@ class RevaDecompilationIndex(RevaRemoteTool):
107
108
  "function_signature": response.function_signature,
108
109
  "address": hex(response.address),
109
110
  "decompilation": response.decompilation,
111
+ "listing": response.listing,
110
112
  "variables": response.variables, #type: ignore # We can ignore this because it can be serialised to a dict
111
113
  }
112
114
 
@@ -226,7 +228,10 @@ class RevaCrossReferenceTool(RevaRemoteTool):
226
228
  These might be calls from/to other functions, or data references from/to this address.
227
229
  """
228
230
  from ..tool_protocol import RevaGetReferences, RevaGetReferencesResponse
229
-
231
+ if isinstance(address_or_symbol, int):
232
+ address_or_symbol = hex(address_or_symbol)
233
+ if not isinstance(address_or_symbol, str):
234
+ raise RevaToolException(f"address_or_symbol must be a string. Provided type was {type(address_or_symbol)}")
230
235
  get_references_message = RevaGetReferences(address_or_symbol=address_or_symbol)
231
236
  response = self.submit_to_tool(get_references_message)
232
237
  assert isinstance(response, RevaMessageResponse), "Incorrect type returned from callback handler."
@@ -274,4 +279,33 @@ class RevaSetSymbolName(RevaRemoteTool):
274
279
  return {
275
280
  "old_name": old_name_or_address,
276
281
  "new_name": new_name,
277
- }
282
+ }
283
+
284
+ @register_tool
285
+ class RevaSetComment(RevaRemoteTool):
286
+ """
287
+ A tool for setting comments on addresses, functions and symbols.
288
+ """
289
+
290
+ def __init__(self, project: AssistantProject, llm: BaseLLM) -> None:
291
+ super().__init__(project, llm)
292
+ self.description = "Used for setting comments on addresses, functions and symbols"
293
+
294
+ self.tool_functions = [
295
+ self.set_comment,
296
+ ]
297
+
298
+ def set_comment(self, comment: str, address_or_symbol: str) -> Dict[str, str]:
299
+ """
300
+ Set the comment at the given address, function or symbol to `comment`.
301
+ Use this when you want to add an explanation or note to a specific part
302
+ of the code.
303
+ """
304
+ from ..tool_protocol import RevaSetComment, RevaSetCommentResponse
305
+ set_comment_message: RevaMessageToTool = RevaSetComment(comment=comment, address_or_symbol=address_or_symbol)
306
+
307
+ response = self.submit_to_tool(set_comment_message)
308
+ assert isinstance(response, RevaSetCommentResponse), f"Expected a RevaSetCommentResponse, got {response}"
309
+ response: RevaSetCommentResponse = response
310
+
311
+ return response.model_dump()
@@ -281,7 +281,7 @@ def run_task(project_name: str):
281
281
 
282
282
  reva_message = RevaMessage.to_specific_message(message) # type: ignore
283
283
  assert isinstance(reva_message, RevaMessageToReva)
284
- reva_message: RevaMessageToReva = reva_message
284
+ reva_message: RevaMessageToReva = reva_message # type: ignore
285
285
 
286
286
  logger.debug(f"Processing message {reva_message}")
287
287
 
@@ -338,7 +338,7 @@ def run_server(port: int = REVA_PORT) -> None:
338
338
  logging.getLogger("werkzeug").setLevel(logging.WARNING)
339
339
  # Import these down here to avoid a circular import
340
340
  # We need to have all the handlers registered before we start
341
- from .api_server_tools import function_tools, llm_tools
341
+ from .api_server_tools import re_tools, llm_tools
342
342
  app.run(host='localhost', port=port, debug=False)
343
343
 
344
344
  def main():
@@ -33,8 +33,10 @@ import json
33
33
  from pathlib import Path
34
34
  import logging
35
35
 
36
+ from click import Option
36
37
  from pydantic import BaseModel, Field
37
38
  import pydantic
39
+ import pydantic_core
38
40
 
39
41
  try:
40
42
  from pydantic import validator
@@ -99,9 +101,11 @@ class RevaMessage(BaseModel, ABC):
99
101
  logger.debug(f"Message class is {message_class}")
100
102
  try:
101
103
  return message_class.model_validate(thing)
102
- except pydantic.error_wrappers.ValidationError:
104
+ except pydantic_core.ValidationError:
105
+ # If we fail to turn it into a specific type, make it a generic type
106
+ # This allows us to extract things like error messages.
103
107
  if issubclass(message_class, RevaMessageResponse):
104
- return RevaMessageResponse.parse_obj(thing)
108
+ return RevaMessageResponse.model_validate(thing)
105
109
  else:
106
110
  logger.exception(f"Failed to parse {thing} as {message_class}")
107
111
  return RevaMessage.model_validate(thing)
@@ -246,9 +250,9 @@ class RevaGetDecompilation(RevaMessageToTool):
246
250
 
247
251
  class RevaVariable(BaseModel):
248
252
  name: str = Field()
249
- storage: Optional[str] = Field()
250
- data_type: Optional[str] = Field()
251
- size: Optional[int] = Field()
253
+ storage: Optional[str] = Field(default=None)
254
+ data_type: Optional[str] = Field(default=None)
255
+ size: Optional[int] = Field(default=None)
252
256
 
253
257
  @register_message
254
258
  class RevaGetDecompilationResponse(RevaMessageToReva, RevaMessageResponse):
@@ -264,6 +268,10 @@ class RevaGetDecompilationResponse(RevaMessageToReva, RevaMessageResponse):
264
268
  """
265
269
  The decompilation of the given address
266
270
  """
271
+ listing: Optional[str] = Field(default=None)
272
+ """
273
+ The disassebly listing of the function
274
+ """
267
275
  function: str = Field()
268
276
  """
269
277
  The function this decompilation is for
@@ -457,4 +465,45 @@ class RevaRenameVariableResponse(RevaMessageToReva, RevaMessageResponse):
457
465
 
458
466
  A simple yes/no, not much to respond with.
459
467
  """
460
- message_type: str = "RevaRenameVariableResponse"
468
+ message_type: str = "RevaRenameVariableResponse"
469
+
470
+ class RevaLocation(BaseModel):
471
+ cursor_address: Optional[str] = Field(default=None)
472
+ function_name: Optional[str] = Field(default=None)
473
+ start_address: Optional[str] = Field(default=None)
474
+ end_address: Optional[str] = Field(default=None)
475
+ content: Optional[str] = Field(default=None)
476
+
477
+ @register_message
478
+ class RevaExplain(RevaMessageToReva):
479
+ """
480
+ Ask the model to explain something
481
+ """
482
+ message_type: str = "RevaExplain"
483
+ location: RevaLocation = Field()
484
+ """
485
+ The location to explain
486
+ """
487
+
488
+ @register_message
489
+ class RevaExplainResponse(RevaMessageToTool, RevaMessageResponse):
490
+ """
491
+ Response to a RevaExplain message
492
+ """
493
+ message_type: str = "RevaExplainResponse"
494
+
495
+ @register_message
496
+ class RevaSetComment(RevaMessageToTool):
497
+ """
498
+ Set a comment at a given address
499
+ """
500
+ message_type: str = "RevaSetComment"
501
+ address_or_symbol: str = Field()
502
+ comment: str = Field()
503
+
504
+ @register_message
505
+ class RevaSetCommentResponse(RevaMessageToReva, RevaMessageResponse):
506
+ """
507
+ Response to a RevaSetComment message
508
+ """
509
+ message_type: str = "RevaSetCommentResponse"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reverse-engineering-assistant
3
- Version: 1.0.1
3
+ Version: 1.0.3
4
4
  Summary: An AI assistant for reverse engineering tasks
5
5
  Author: サイバーカイダ (cyberkaida)
6
6
  Classifier: License :: OSI Approved :: Apache Software License
@@ -145,6 +145,8 @@ revassistant --project ${NAME_OF_YOUR_PROJECT}
145
145
 
146
146
  ## Usage
147
147
 
148
+ The [ghidra-assistant](ghidra-assistant/README.md) plugin must be installed first.
149
+
148
150
  After installation, enable the `ReVaPlugin` extension in the CodeBrowser tool (Open a file and click: File -> Configure -> Miscellaneous).
149
151
 
150
152
  If you want ReVa enabled by default, click File -> Save Tool to save the configuration.
@@ -16,5 +16,5 @@ reverse_engineering_assistant.egg-info/entry_points.txt
16
16
  reverse_engineering_assistant.egg-info/requires.txt
17
17
  reverse_engineering_assistant.egg-info/top_level.txt
18
18
  reverse_engineering_assistant/api_server_tools/__init__.py
19
- reverse_engineering_assistant/api_server_tools/function_tools.py
20
- reverse_engineering_assistant/api_server_tools/llm_tools.py
19
+ reverse_engineering_assistant/api_server_tools/llm_tools.py
20
+ reverse_engineering_assistant/api_server_tools/re_tools.py