reverse-engineering-assistant 1.0.3__tar.gz → 2.9.2__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 (63) hide show
  1. {reverse-engineering-assistant-1.0.3 → reverse_engineering_assistant-2.9.2}/PKG-INFO +82 -67
  2. reverse_engineering_assistant-2.9.2/README.md +183 -0
  3. {reverse-engineering-assistant-1.0.3 → reverse_engineering_assistant-2.9.2}/pyproject.toml +6 -6
  4. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/.gitignore +2 -0
  5. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/api_server_tools/__init__.py +16 -0
  6. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/api_server_tools/connection.py +24 -0
  7. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/api_server_tools/llm_tools.py +159 -0
  8. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/api_server_tools/re_tools.py +504 -0
  9. {reverse-engineering-assistant-1.0.3 → reverse_engineering_assistant-2.9.2}/reverse_engineering_assistant/assistant.py +99 -126
  10. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/assistant_api_server.py +159 -0
  11. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/chat_client.py +205 -0
  12. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/model.py +68 -0
  13. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaChat_pb2.py +31 -0
  14. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaChat_pb2.pyi +27 -0
  15. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaChat_pb2_grpc.py +190 -0
  16. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaComment_pb2.py +31 -0
  17. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaComment_pb2.pyi +17 -0
  18. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaComment_pb2_grpc.py +101 -0
  19. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaData_pb2.py +39 -0
  20. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaData_pb2.pyi +72 -0
  21. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaData_pb2_grpc.py +187 -0
  22. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaGetCursor_pb2.py +31 -0
  23. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaGetCursor_pb2.pyi +19 -0
  24. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaGetCursor_pb2_grpc.py +101 -0
  25. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaGetDecompilation_pb2.py +40 -0
  26. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaGetDecompilation_pb2.pyi +69 -0
  27. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaGetDecompilation_pb2_grpc.py +187 -0
  28. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaGetReferences_pb2.py +31 -0
  29. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaGetReferences_pb2.pyi +20 -0
  30. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaGetReferences_pb2_grpc.py +101 -0
  31. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaGetSymbols_pb2.py +47 -0
  32. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaGetSymbols_pb2.pyi +68 -0
  33. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaGetSymbols_pb2_grpc.py +258 -0
  34. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaHandshake_pb2.py +31 -0
  35. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaHandshake_pb2.pyi +21 -0
  36. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaHandshake_pb2_grpc.py +101 -0
  37. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaHeartbeat_pb2.py +31 -0
  38. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaHeartbeat_pb2.pyi +23 -0
  39. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaHeartbeat_pb2_grpc.py +101 -0
  40. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaVariable_pb2.py +27 -0
  41. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaVariable_pb2.pyi +17 -0
  42. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol/RevaVariable_pb2_grpc.py +29 -0
  43. {reverse-engineering-assistant-1.0.3 → reverse_engineering_assistant-2.9.2}/reverse_engineering_assistant.egg-info/PKG-INFO +82 -67
  44. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant.egg-info/SOURCES.txt +52 -0
  45. reverse_engineering_assistant-2.9.2/reverse_engineering_assistant.egg-info/entry_points.txt +3 -0
  46. {reverse-engineering-assistant-1.0.3 → reverse_engineering_assistant-2.9.2}/reverse_engineering_assistant.egg-info/requires.txt +4 -2
  47. reverse-engineering-assistant-1.0.3/README.md +0 -170
  48. reverse-engineering-assistant-1.0.3/reverse_engineering_assistant/api_server_tools/llm_tools.py +0 -67
  49. reverse-engineering-assistant-1.0.3/reverse_engineering_assistant/api_server_tools/re_tools.py +0 -311
  50. reverse-engineering-assistant-1.0.3/reverse_engineering_assistant/assistant_api_server.py +0 -355
  51. reverse-engineering-assistant-1.0.3/reverse_engineering_assistant/configuration.py +0 -151
  52. reverse-engineering-assistant-1.0.3/reverse_engineering_assistant/model.py +0 -109
  53. reverse-engineering-assistant-1.0.3/reverse_engineering_assistant/tool_protocol.py +0 -509
  54. reverse-engineering-assistant-1.0.3/reverse_engineering_assistant.egg-info/SOURCES.txt +0 -20
  55. reverse-engineering-assistant-1.0.3/reverse_engineering_assistant.egg-info/entry_points.txt +0 -4
  56. {reverse-engineering-assistant-1.0.3 → reverse_engineering_assistant-2.9.2}/reverse_engineering_assistant/__init__.py +0 -0
  57. {reverse-engineering-assistant-1.0.3 → reverse_engineering_assistant-2.9.2}/reverse_engineering_assistant/documents.py +0 -0
  58. {reverse-engineering-assistant-1.0.3/reverse_engineering_assistant/api_server_tools → reverse_engineering_assistant-2.9.2/reverse_engineering_assistant/protocol}/__init__.py +0 -0
  59. {reverse-engineering-assistant-1.0.3 → reverse_engineering_assistant-2.9.2}/reverse_engineering_assistant/reva_exceptions.py +0 -0
  60. {reverse-engineering-assistant-1.0.3 → reverse_engineering_assistant-2.9.2}/reverse_engineering_assistant/tool.py +0 -0
  61. {reverse-engineering-assistant-1.0.3 → reverse_engineering_assistant-2.9.2}/reverse_engineering_assistant.egg-info/dependency_links.txt +0 -0
  62. {reverse-engineering-assistant-1.0.3 → reverse_engineering_assistant-2.9.2}/reverse_engineering_assistant.egg-info/top_level.txt +0 -0
  63. {reverse-engineering-assistant-1.0.3 → reverse_engineering_assistant-2.9.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reverse-engineering-assistant
3
- Version: 1.0.3
3
+ Version: 2.9.2
4
4
  Summary: An AI assistant for reverse engineering tasks
5
5
  Author: サイバーカイダ (cyberkaida)
6
6
  Classifier: License :: OSI Approved :: Apache Software License
@@ -11,17 +11,19 @@ Description-Content-Type: text/markdown
11
11
  Requires-Dist: langchain
12
12
  Requires-Dist: langchain-core
13
13
  Requires-Dist: langchain-openai
14
- Requires-Dist: llama-cpp-python
14
+ Requires-Dist: langchain-community
15
15
  Requires-Dist: prompt_toolkit
16
16
  Requires-Dist: sentence_transformers
17
17
  Requires-Dist: PyYAML
18
18
  Requires-Dist: pydantic
19
19
  Requires-Dist: rich
20
- Requires-Dist: Flask
20
+ Requires-Dist: grpcio
21
+ Requires-Dist: protobuf
22
+ Requires-Dist: flask
21
23
 
22
24
  # ReVA - Reverse Engineering Assistant
23
25
 
24
- [✨ An (old) quick demo! ✨](https://asciinema.org/a/626197)
26
+ > Updated demo coming soon!
25
27
 
26
28
  The reverse engineering assistant (ReVA) is a project to build a disassembler agnostic AI assistant for
27
29
  reverse engineering tasks. This includes both _offline_ and online inference and a simple architecture.
@@ -46,13 +48,14 @@ information from the tools, but when there is no information it can still respon
46
48
  questions from its training.
47
49
 
48
50
  You can ask questions like:
51
+ - What are the interesting strings in this program?
49
52
  - Does this program use encryption? Write a markdown report on the encryption and where it is used.
50
53
  - Draw a class diagram using plantuml syntax.
51
54
  - Start from main, examine the program in detail. Rename variables as you go and provide a summary of the program.
52
55
  - Explain the purpose of the `__mod_init` segment.
53
56
  - What does `mmap` return?
54
57
  - What does the function at address 0x80000 do?
55
- - This is a CTF problem. Start at main, examine the program in detail and write a pwntools script to get the flag.
58
+ - This is a CTF problem. Write a pwntools script to get the flag.
56
59
 
57
60
  An important part of reverse engineering is the process. Many other tools simply ask a single question of the LLM,
58
61
  this means it is difficult to determine _why_ a thing happened. In ReVa we break all actions down into small parts
@@ -68,36 +71,40 @@ Built in support is provided for:
68
71
  - [OpenAI](https://platform.openai.com/overview) for online inference and easy setup (Needs an OpenAI API key)
69
72
  - [Ollama](https://ollama.ai) and any model it supports for local on-device inference or connecting to a self hosted remote inference server.
70
73
 
71
- Limited support is provided for:
72
- - [llama-cpp](https://llama-cpp-python.readthedocs.io/en/latest/) and any model it supports for local on-device inference
73
- - [text-generation-webui](https://github.com/oobabooga/text-generation-webui) and any model it supports for self-hosted remote inference
74
+ See [Configuration](#configuration) for more information about settings for the providers.
74
75
 
75
76
  Adding additional inference servers is easy if it is supported by langchain.
76
77
 
77
- See the configuration section for more information about setting the model.
78
-
79
78
  ## Configuration
80
79
 
81
- Configuration for the reverse engineering assistant is stored at
82
- `~/.config/reverse-engineering-assistant/config.yaml`. If this
83
- is not present on first start, a default configuration using
84
- OpenAI for inference and the `OPENAI_API_TOKEN` environment
85
- variable will be used.
80
+ Configuration for ReVa is in the CodeBrowser Tool options.
81
+ Open a program and go to Edit -> Tool Options -> ReVa.
82
+
83
+ There are options for:
84
+ - Selecting a provider (OpenAI or Ollama, others coming soon!)
85
+ - Enabling "Follow", this will move the Ghidra view to the location of
86
+ things ReVa is examining or changing.
87
+ - Enabling "Auto-allow", ReVa will log her actions for the user to accept
88
+ in the "ReVa Actions Log" window.
89
+
90
+ There are sections for the providers.
91
+
92
+ ### OpenAI
86
93
 
87
- The most important setting is the `type` top level setting.
88
- This controls what inference service you use. These are the
89
- same as the configuration keys, for example to use Ollama,
90
- set type to `ollama` and configure the settings in the `ollama:`
91
- section.
94
+ By default, the OpenAI key is loaded from the environment variable `OPENAI_API_KEY`. You can also set your key inside Ghidra. Setting the key back to the `OPENAI_API_KEY` value will clear the key from the Ghidra configuration and load it from the environment.
92
95
 
93
- The configuration also contains the prompts used for the models.
94
- If you use Ollama or OpenAI these will be processed to fit the
95
- model specific prompt pattern (placing the system prompt in the
96
- correct tags, etc).
96
+ You can also select the model. By default `gpt-4o` is selected. This model works best with the tools and the prompt provided by ReVa.
97
97
 
98
- For `llama-cpp` and `text-generation-webui` these may need to be
99
- configured for your specific model. For this reason Ollama is
100
- preferred for self hosting.
98
+ `gpt-4` also works well, but is slow and needs more prompting by the user to explore a binary.
99
+
100
+ ### Ollama
101
+
102
+ Ollama is a local inference server. The default server is set to localhost, with the default Ollama port. You can change this to a remote server if you want to perform inference on a remote machine. This is useful for organisations that self host.
103
+
104
+ You can also select a model. The model must alread be loaded on the server. Good performance has been seen with:
105
+ - `mixtral`
106
+ - `llama3`
107
+ - `phi`
101
108
 
102
109
  ## Workflow
103
110
 
@@ -106,54 +113,68 @@ RevA has a two step workflow.
106
113
  2. Open the chat session.
107
114
 
108
115
  ReVa uses an extension for your RE tool to perform analysis.
109
- See [Ghidra Support](#ghidra-support) and [BinaryNinja Support](#binary-ninja-support) below.
116
+ See [Ghidra Support](#ghidra-support) below.
110
117
 
111
- Once open the RE tool will try to connect to ReVa's REST API on localhost.
118
+ To ask questions and run the inference a command line tool is provided. Run `reva-chat` to begin the chat session. This command will find your open Ghidra
119
+ and connect to it. To open a new chat, run the command again in another terminal.
112
120
 
113
- A project cache is created in `~/.cache/reverse-engineering-assistant/projects`. This contains your chat log and other
114
- cache data. This can be deleted at any time and ReVa will re-generate the data as needed.
121
+ If you have more than one Ghidra open, you can select the right one with
122
+ `reva-chat --project ${project-name}`, if it is not set, `reva-chat` will
123
+ ask you which project you want to connect to.
115
124
 
116
- To ask questions and run the inference a command line tool is provided. Run `revassistant --project ${NAME_OF_YOUR_FILE}` to begin the chat session.
125
+ ## Protocol Build
117
126
 
118
- > Note: In the future `--project` will refer to a _project_ in Ghidra and allow inference across multiple files.
119
- > I am waiting for BinaryNinja's project feature to make this change, if this takes too long I will rework this argument.
127
+ To communicate between `reva-server` and the extension, [gRPC](https://grpc.io) is used. You can read more about that (here)[./DEVELOPER.md]. Building the source files from those protocol definitions is driven from the [Makefile](/Makefile). To build the protocol source code files, run this command in the project's root:
120
128
 
121
- `revassistant` provides a chat window and runs the command API to talk with the RE tool.
129
+ ```sh
130
+ make protocol
131
+ ```
122
132
 
123
- > Note: Right now only one `revassistant` can run at a time (as we start a server on a well known port)
124
- > In the future we will share the server between chat clients and RE tool connections.
133
+ ## Python Project (reva-server and reva-chat) Installation
125
134
 
126
- ## Installation
135
+ First install the python component, I like to use `pipx`. Install it with something like:
127
136
 
128
- To install the particular extension for your disassembler see:
129
- - [Ghidra Support](#ghidra-support)
130
- - [Binary Ninja Support](#binary-ninja-support)
137
+ ```sh
138
+ pip install pipx
139
+ ```
131
140
 
132
- To install the chat component you can do the following:
141
+ In the `reverse-engineering-assistant` folder, run:
133
142
 
134
143
  ```sh
135
- python3 -m pip install ./reverse-engineering-assistant
144
+ pipx install .
136
145
  ```
137
146
 
138
- The chat can be started with:
147
+ After installing the python project, pipx may warn you that you need to add a folder to your PATH environment variable. Make sure that the folder (now containing `reva-server` and `reva-chat`) are in your PATH variable. pipx can do it for you with this command:
139
148
 
140
149
  ```sh
141
- revassistant --project ${NAME_OF_YOUR_PROJECT}
150
+ pipx ensurepath
151
+ ```
152
+
153
+ The extension will need to start `reva-server`, and you will need to run `reva-chat`. In case you do not want to add them to your PATH, see the [Configuration](#configuration) section for how to set the path to the executables.
154
+
155
+ Once the `reva-server` has been started by the extension the chat can be started with:
156
+
157
+ ```sh
158
+ reva-chat
142
159
  ```
143
160
 
144
161
  # Ghidra Support
145
162
 
146
163
  ## Usage
147
164
 
148
- The [ghidra-assistant](ghidra-assistant/README.md) plugin must be installed first.
165
+ > The Python package must be installed for the Ghidra extension to work!
166
+
167
+ Follow the instructions in the [ghidra-assistant](ghidra-assistant/README.md) plugin.
149
168
 
150
- After installation, enable the `ReVaPlugin` extension in the CodeBrowser tool (Open a file and click: File -> Configure -> Miscellaneous).
169
+ After installation, enable the `ReVa Plugin` extension in the CodeBrowser tool (Open a file and click: File -> Configure -> Miscellaneous).
151
170
 
152
171
  If you want ReVa enabled by default, click File -> Save Tool to save the configuration.
153
172
 
154
- To start the inference side, open Help -> About ${program name}. In this popup you will see details about your open file.
155
- The `Program Name:` field is the name you need to pass to `revassistant --project` to start the inference server. In some
156
- cases this is different to the name in the project view.
173
+ If everything is working correctly you will see a ReVa menu on your menu bar.
174
+
175
+ ## Configuration
176
+
177
+ You can modify the plugin configuration in `Edit -> Tool Options -> ReVa`.
157
178
 
158
179
  ## Undo
159
180
 
@@ -162,28 +183,22 @@ one undo.
162
183
 
163
184
  ## Menus
164
185
 
165
- ReVa adds some elements to the Ghidra UI. You can either ask ReVa to do something in the chat window,
166
- "Examine the variable usage in `main` in detail, rename the variables with more descriptive names.",
167
- or use the menu system.
168
-
169
- For example you can right click a variable in the decompilation, select Reva -> Rename variable and ReVa
170
- will perform the action.
186
+ ReVa adds an option to the CodeBrowser Tool's Window menu.
187
+ Select Window -> ReVa Action Log to open the ReVa Action Log window.
171
188
 
172
- Note this uses the same system as chatting with ReVa, this means you can monitor ReVas thoughts in the chat
173
- window while the action is performed.
189
+ This window shows actions ReVa has performed and would like to perform.
190
+ You can accept or reject a change by double clicking the ✅ or ❌ icon. You can also go to the location the action will be performed by double clicking the address.
174
191
 
175
- # Binary Ninja Support
192
+ If you reject an action, ReVa will be told and she will move on.
176
193
 
177
- > Note: Binary Ninja support is currently on hold while the basic functions are implemented in the Ghidra plugin.
178
- > This is because plugin development for Binary Ninja is easier as we have Python3. I will resume development soon!
194
+ You can also enable "Auto-allow" in the ReVa options. This will automatically accept all actions ReVa wants to perform.
179
195
 
180
- Install the ReVA BinaryNinja plugin by opening your BinaryNinja plugin directory (Plugins -> Open Plugin Folder)
181
- and copying or symbolic linking the [binary-ninja-assistant](./binary-ninja-assistant) directory into the plugin
182
- directory.
196
+ ReVa also adds some elements to the Ghidra UI. You can either ask ReVa to do something in the chat window,
197
+ "Examine the variable usage in `main` in detail, rename the variables with more descriptive names.",
198
+ or use the menu system.
183
199
 
184
- Restart Binary Ninja and "ReVA Push" will be available in the Plugin menu.
185
- Press this to push data from BinaryNinja to ReVA, then follow the instructions in the [Workflow section](#workflow).
186
- The project name will be the name of the current open file.
200
+ For example you can right click a variable in the decompilation, select Reva -> Rename variable and ReVa
201
+ will perform the action.
187
202
 
188
203
  # Support
189
204
 
@@ -0,0 +1,183 @@
1
+ # ReVA - Reverse Engineering Assistant
2
+
3
+ > Updated demo coming soon!
4
+
5
+ The reverse engineering assistant (ReVA) is a project to build a disassembler agnostic AI assistant for
6
+ reverse engineering tasks. This includes both _offline_ and online inference and a simple architecture.
7
+
8
+ ReVa is different from other efforts at building AI assistants for RE tasks because it uses a _tool driven approach_.
9
+ ReVa aims to provide a variety of small tools to the LLM, just as your RE environment provides a set of small tools
10
+ to you. ReVa combines this approach with chain-of-reasoning techniques to empower the LLM to complete complex tasks.
11
+
12
+ Each of the tools given to the LLM are constructed to be easy for the LLM to use and to tolerate a variety of inputs
13
+ and to reduce hallucination by the LLM. We do this by providing the LLM with a schema but tolerating other input,
14
+ including descriptions that guide the LLM,and redirecting correctable mistakes back to the LLM, and including extra
15
+ output to guide the next decision by the LLM.
16
+
17
+ For example, when the LLM requests decompilation from your RE tool, we will accept a raw address in hex, a raw address
18
+ in base 10, a symbol name with a namespace, or a symbol. If the LLM gives us bad input we report this to the LLM along
19
+ with instructions to correct the input (maybe encouraging it to use the function list for example). To encourage exploration
20
+ as a human would, we report additional context like the namespace and cross references along with the decompilation, this
21
+ is a small nudge to make the LLM explore the binary in the same way a human would.
22
+
23
+ Using this technique you can ask general questions and get relevant answers. The model prioritises
24
+ information from the tools, but when there is no information it can still respond to generic
25
+ questions from its training.
26
+
27
+ You can ask questions like:
28
+ - What are the interesting strings in this program?
29
+ - Does this program use encryption? Write a markdown report on the encryption and where it is used.
30
+ - Draw a class diagram using plantuml syntax.
31
+ - Start from main, examine the program in detail. Rename variables as you go and provide a summary of the program.
32
+ - Explain the purpose of the `__mod_init` segment.
33
+ - What does `mmap` return?
34
+ - What does the function at address 0x80000 do?
35
+ - This is a CTF problem. Write a pwntools script to get the flag.
36
+
37
+ An important part of reverse engineering is the process. Many other tools simply ask a single question of the LLM,
38
+ this means it is difficult to determine _why_ a thing happened. In ReVa we break all actions down into small parts
39
+ and include the LLMs thoughts in the output. This allows the analyst to monitor the LLMs actions and reasoning, aborting
40
+ and changing the prompt if required.
41
+
42
+ ## Large Language Model Support
43
+
44
+ RevA is based on [langchain](https://langchain.com),
45
+ which supports a number of models.
46
+
47
+ Built in support is provided for:
48
+ - [OpenAI](https://platform.openai.com/overview) for online inference and easy setup (Needs an OpenAI API key)
49
+ - [Ollama](https://ollama.ai) and any model it supports for local on-device inference or connecting to a self hosted remote inference server.
50
+
51
+ See [Configuration](#configuration) for more information about settings for the providers.
52
+
53
+ Adding additional inference servers is easy if it is supported by langchain.
54
+
55
+ ## Configuration
56
+
57
+ Configuration for ReVa is in the CodeBrowser Tool options.
58
+ Open a program and go to Edit -> Tool Options -> ReVa.
59
+
60
+ There are options for:
61
+ - Selecting a provider (OpenAI or Ollama, others coming soon!)
62
+ - Enabling "Follow", this will move the Ghidra view to the location of
63
+ things ReVa is examining or changing.
64
+ - Enabling "Auto-allow", ReVa will log her actions for the user to accept
65
+ in the "ReVa Actions Log" window.
66
+
67
+ There are sections for the providers.
68
+
69
+ ### OpenAI
70
+
71
+ By default, the OpenAI key is loaded from the environment variable `OPENAI_API_KEY`. You can also set your key inside Ghidra. Setting the key back to the `OPENAI_API_KEY` value will clear the key from the Ghidra configuration and load it from the environment.
72
+
73
+ You can also select the model. By default `gpt-4o` is selected. This model works best with the tools and the prompt provided by ReVa.
74
+
75
+ `gpt-4` also works well, but is slow and needs more prompting by the user to explore a binary.
76
+
77
+ ### Ollama
78
+
79
+ Ollama is a local inference server. The default server is set to localhost, with the default Ollama port. You can change this to a remote server if you want to perform inference on a remote machine. This is useful for organisations that self host.
80
+
81
+ You can also select a model. The model must alread be loaded on the server. Good performance has been seen with:
82
+ - `mixtral`
83
+ - `llama3`
84
+ - `phi`
85
+
86
+ ## Workflow
87
+
88
+ RevA has a two step workflow.
89
+ 1. Open your RE tool and the program you want to examine
90
+ 2. Open the chat session.
91
+
92
+ ReVa uses an extension for your RE tool to perform analysis.
93
+ See [Ghidra Support](#ghidra-support) below.
94
+
95
+ To ask questions and run the inference a command line tool is provided. Run `reva-chat` to begin the chat session. This command will find your open Ghidra
96
+ and connect to it. To open a new chat, run the command again in another terminal.
97
+
98
+ If you have more than one Ghidra open, you can select the right one with
99
+ `reva-chat --project ${project-name}`, if it is not set, `reva-chat` will
100
+ ask you which project you want to connect to.
101
+
102
+ ## Protocol Build
103
+
104
+ To communicate between `reva-server` and the extension, [gRPC](https://grpc.io) is used. You can read more about that (here)[./DEVELOPER.md]. Building the source files from those protocol definitions is driven from the [Makefile](/Makefile). To build the protocol source code files, run this command in the project's root:
105
+
106
+ ```sh
107
+ make protocol
108
+ ```
109
+
110
+ ## Python Project (reva-server and reva-chat) Installation
111
+
112
+ First install the python component, I like to use `pipx`. Install it with something like:
113
+
114
+ ```sh
115
+ pip install pipx
116
+ ```
117
+
118
+ In the `reverse-engineering-assistant` folder, run:
119
+
120
+ ```sh
121
+ pipx install .
122
+ ```
123
+
124
+ After installing the python project, pipx may warn you that you need to add a folder to your PATH environment variable. Make sure that the folder (now containing `reva-server` and `reva-chat`) are in your PATH variable. pipx can do it for you with this command:
125
+
126
+ ```sh
127
+ pipx ensurepath
128
+ ```
129
+
130
+ The extension will need to start `reva-server`, and you will need to run `reva-chat`. In case you do not want to add them to your PATH, see the [Configuration](#configuration) section for how to set the path to the executables.
131
+
132
+ Once the `reva-server` has been started by the extension the chat can be started with:
133
+
134
+ ```sh
135
+ reva-chat
136
+ ```
137
+
138
+ # Ghidra Support
139
+
140
+ ## Usage
141
+
142
+ > The Python package must be installed for the Ghidra extension to work!
143
+
144
+ Follow the instructions in the [ghidra-assistant](ghidra-assistant/README.md) plugin.
145
+
146
+ After installation, enable the `ReVa Plugin` extension in the CodeBrowser tool (Open a file and click: File -> Configure -> Miscellaneous).
147
+
148
+ If you want ReVa enabled by default, click File -> Save Tool to save the configuration.
149
+
150
+ If everything is working correctly you will see a ReVa menu on your menu bar.
151
+
152
+ ## Configuration
153
+
154
+ You can modify the plugin configuration in `Edit -> Tool Options -> ReVa`.
155
+
156
+ ## Undo
157
+
158
+ Whenever ReVa performs an action it will create an undo point for each action. If ReVa renames 5 variables, this will be
159
+ one undo.
160
+
161
+ ## Menus
162
+
163
+ ReVa adds an option to the CodeBrowser Tool's Window menu.
164
+ Select Window -> ReVa Action Log to open the ReVa Action Log window.
165
+
166
+ This window shows actions ReVa has performed and would like to perform.
167
+ You can accept or reject a change by double clicking the ✅ or ❌ icon. You can also go to the location the action will be performed by double clicking the address.
168
+
169
+ If you reject an action, ReVa will be told and she will move on.
170
+
171
+ You can also enable "Auto-allow" in the ReVa options. This will automatically accept all actions ReVa wants to perform.
172
+
173
+ ReVa also adds some elements to the Ghidra UI. You can either ask ReVa to do something in the chat window,
174
+ "Examine the variable usage in `main` in detail, rename the variables with more descriptive names.",
175
+ or use the menu system.
176
+
177
+ For example you can right click a variable in the decompilation, select Reva -> Rename variable and ReVa
178
+ will perform the action.
179
+
180
+ # Support
181
+
182
+ Do you like my work? Want to support this project and others? Interested in how this project was designed and built?
183
+ This project and many others are built live on my stream at https://twitch.tv/cyberkaida !
@@ -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.3"
8
+ version = "2.9.2"
9
9
  authors = [
10
10
  {name="サイバーカイダ (cyberkaida)"},
11
11
  ]
@@ -20,17 +20,17 @@ dependencies = [
20
20
  "langchain",
21
21
  "langchain-core",
22
22
  "langchain-openai",
23
- "llama-cpp-python",
23
+ "langchain-community",
24
24
  "prompt_toolkit",
25
25
  "sentence_transformers",
26
26
  "PyYAML",
27
27
  "pydantic",
28
28
  "rich",
29
- "Flask",
29
+ "grpcio",
30
+ "protobuf",
31
+ "flask",
30
32
  ]
31
33
 
32
34
  [project.scripts]
33
- revassistant = "reverse_engineering_assistant.assistant:main"
34
- reva-serve = "reverse_engineering_assistant.assistant_api_server:main"
35
35
  reva-server = "reverse_engineering_assistant.assistant_api_server:main"
36
-
36
+ reva-chat = "reverse_engineering_assistant.chat_client:main"
@@ -0,0 +1,16 @@
1
+
2
+
3
+ from typing import List
4
+
5
+
6
+ class RevaMessageHandler(object):
7
+ handles_type = None
8
+
9
+
10
+ _global_message_handlers: List[RevaMessageHandler] = []
11
+
12
+ __all__ = ['register_message_handler']
13
+
14
+ def register_message_handler(cls: RevaMessageHandler):
15
+ _global_message_handlers.append(cls)
16
+ return cls
@@ -0,0 +1,24 @@
1
+ from pathlib import Path
2
+ import sys
3
+ sys.path.append(str(Path(__file__).parent.joinpath('protocol')))
4
+ import grpc
5
+ from grpc import Channel, Server
6
+
7
+ from typing import Optional
8
+
9
+ from functools import cache
10
+
11
+ _channel: Optional[Channel] = None
12
+ @cache
13
+ def get_channel() -> Channel:
14
+ global _channel
15
+ if not _channel:
16
+ raise ValueError("Channel not set")
17
+ return _channel
18
+
19
+ @cache
20
+ def connect_to_extension(host: str, port: int) -> Channel:
21
+ channel: Channel = grpc.insecure_channel(f"{host}:{port}")
22
+ global _channel
23
+ _channel = channel
24
+ return get_channel()
@@ -0,0 +1,159 @@
1
+
2
+
3
+ from ast import Call
4
+ import queue
5
+ import threading
6
+ from typing import Callable, Dict, Optional
7
+ from venv import logger
8
+
9
+ from ..protocol.RevaChat_pb2_grpc import RevaChatServiceServicer
10
+ from ..protocol.RevaChat_pb2 import RevaChatMessageResponse
11
+
12
+ from functools import cache
13
+ from ..assistant import ReverseEngineeringAssistant
14
+
15
+ import logging
16
+ module_logger = logging.getLogger("reva-server")
17
+
18
+ from langchain_core.callbacks.base import BaseCallbackHandler
19
+ from langchain_core.agents import AgentAction, AgentFinish
20
+
21
+ from langchain_core.language_models.base import BaseLanguageModel
22
+ from langchain_core.language_models.chat_models import BaseChatModel
23
+
24
+ class RevaActionCollector(BaseCallbackHandler):
25
+ """
26
+ A callback handler for logging agent actions in the reverse engineering assistant.
27
+
28
+ This class logs agent actions and calls a callback. This is what prints the green
29
+ thoughts from the model to the console. This is very useful for the analyst to understand
30
+ what the model is doing (and is arguably the most important part of the assistant output!)
31
+
32
+ Attributes:
33
+ callback (Callable[[str], None]): The callback function to call when an agent action is performed.
34
+ logger (logging.Logger): The logger instance for the reverse_engineering_assistant.RevaActionLogger class.
35
+ """
36
+
37
+ callback: Callable[[str], None]
38
+ def __init__(self, callback: Callable[[str], None]) -> None:
39
+ super().__init__()
40
+ self.callback = callback
41
+
42
+ logger = logging.getLogger("reverse_engineering_assistant.RevaActionLogger")
43
+
44
+ def on_agent_action(self, action: AgentAction, **kwargs) -> None:
45
+ """
46
+ Callback method called when an agent action is performed.
47
+
48
+ Args:
49
+ action (AgentAction): The agent action that was performed.
50
+ **kwargs: Additional keyword arguments.
51
+
52
+ Returns:
53
+ None
54
+ """
55
+ logger.debug(f"Agent action: {action} {kwargs}")
56
+ # TODO: Should this be AgentAction?
57
+ # TODO: Is `.action` still a thing?
58
+ self.callback(str(action.log))
59
+
60
+
61
+ class RevaChat(RevaChatServiceServicer):
62
+ logger = logging.getLogger("reva-server.RevaChat")
63
+ llm: BaseLanguageModel | BaseChatModel
64
+
65
+ def __init__(self, llm: BaseLanguageModel | BaseChatModel) -> None:
66
+ self.llm = llm
67
+
68
+ def chat(self, request, context):
69
+ self.logger.info(f"Received request: {request}")
70
+ assistant = ReverseEngineeringAssistant(
71
+ request.project,
72
+ model=self.llm
73
+ )
74
+ self.logger.info(f"Assistant: {assistant}")
75
+ llm_response = assistant.query(request.message)
76
+ self.logger.info(f"LLM Response: {llm_response}")
77
+ response = RevaChatMessageResponse()
78
+ response.message = llm_response
79
+ return response
80
+
81
+ def chatResponseStream(self, request, context):
82
+ """
83
+ Given a request, return a stream of responses including
84
+ thoughts and a final message from the LLM.
85
+ """
86
+ self.logger.info(f"Received request: {request}")
87
+
88
+ response_queue: queue.Queue = queue.Queue()
89
+
90
+ def callback(message: str):
91
+ # Called for intermediate thoughts
92
+ response = RevaChatMessageResponse()
93
+ response.thought = message
94
+ response_queue.put(response)
95
+
96
+ assistant = ReverseEngineeringAssistant(
97
+ request.project,
98
+ model=self.llm,
99
+ langchain_callbacks=[RevaActionCollector(callback)]
100
+ )
101
+ self.logger.info(f"Assistant: {assistant}")
102
+
103
+ def run_query(query: str):
104
+ llm_response = assistant.query(query)
105
+ self.logger.info(f"LLM Response: {llm_response}")
106
+ response = RevaChatMessageResponse()
107
+ response.message = llm_response
108
+ response_queue.put(response)
109
+
110
+ t = threading.Thread(target=run_query, args=[request.message])
111
+ t.start()
112
+
113
+ done = False
114
+ while not done:
115
+ response = response_queue.get()
116
+ # We stop when we get a message and not thoughts
117
+ if response.message and not response.thought:
118
+ done = True
119
+ yield response
120
+ t.join()
121
+
122
+ def chatStream(self, request_iterator, context):
123
+ assistant: Optional[ReverseEngineeringAssistant] = None
124
+ response_queue: queue.Queue = queue.Queue()
125
+
126
+ def callback(message: str):
127
+ # Called for intermediate thoughts
128
+ response = RevaChatMessageResponse()
129
+ response.thought = message
130
+ response_queue.put(response)
131
+
132
+ for request in request_iterator:
133
+ if not assistant:
134
+ assistant = ReverseEngineeringAssistant(
135
+ request.project,
136
+ model=self.llm,
137
+ langchain_callbacks=[RevaActionCollector(callback)]
138
+ )
139
+ self.logger.info(f"Received request: {request}")
140
+ def run_query(query: str):
141
+ assert assistant is not None
142
+ self.logger.info(f"Asking assistant: {query}")
143
+ llm_response = assistant.query(query)
144
+ self.logger.info(f"LLM Response: {llm_response}")
145
+ response = RevaChatMessageResponse()
146
+ response.message = llm_response
147
+ response_queue.put(response)
148
+
149
+ t = threading.Thread(target=run_query, args=[request.message])
150
+ t.start()
151
+
152
+ done = False
153
+ while not done:
154
+ response = response_queue.get()
155
+ # We stop when we get a message and not thoughts
156
+ if response.message and not response.thought:
157
+ done = True
158
+ yield response
159
+ t.join()