Skip to content

Commit

Permalink
[WIP] tracer: Show contextual disassembly
Browse files Browse the repository at this point in the history
  • Loading branch information
oleavr committed Sep 22, 2024
1 parent b0b1ff2 commit a270ecf
Show file tree
Hide file tree
Showing 13 changed files with 553 additions and 166 deletions.
13 changes: 12 additions & 1 deletion agents/tracer/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class Agent {
message: e.message
});
});

return Process.mainModule;
}

dispose() {
Expand Down Expand Up @@ -98,6 +100,14 @@ class Agent {
return [...nativeIds, ...javaIds];
}

readMemory(address: string, size: number): ArrayBuffer | null {
try {
return ptr(address).readByteArray(size);
} catch (e) {
return null;
}
}

private cropStagedPlan(plan: TracePlan, id: StagedItemId): TracePlan {
let candidateId: StagedItemId;

Expand Down Expand Up @@ -993,5 +1003,6 @@ rpc.exports = {
dispose: agent.dispose.bind(agent),
update: agent.update.bind(agent),
stageTargets: agent.stageTargets.bind(agent),
commitTargets: agent.commitTargets.bind(agent,)
commitTargets: agent.commitTargets.bind(agent),
readMemory: agent.readMemory.bind(agent),
};
25 changes: 25 additions & 0 deletions apps/tracer/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,31 @@
position: absolute !important;
}

.bottom-tabs {
display: flex;
flex-direction: column;
flex: 1;
}

.bp5-tab-list {
padding-left: 5px;
}

.bp5-tab:focus {
outline: 0;
}

.bottom-tab-panel {
display: flex;
margin-top: 5px;
flex: 1;
overflow: hidden;
}

.event-view {
flex: 1;
}

.disassembly-view {
flex: 1;
}
222 changes: 60 additions & 162 deletions apps/tracer/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,137 +1,70 @@
import "./App.css";
import AddTargetsDialog from "./AddTargetsDialog.tsx";
import DisassemblyView from "./DisassemblyView.tsx";
import EventView from "./EventView.tsx";
import HandlerEditor from "./HandlerEditor.tsx";
import HandlerList from "./HandlerList.tsx";
import {
Event,
Handler,
HandlerId,
ScopeId,
StagedItem,
StagedItemId,
TraceSpecScope
} from "./model.js";
import { useModel } from "./model.js";
import {
BlueprintProvider,
Callout,
Button,
ButtonGroup,
Tabs,
Tab,
} from "@blueprintjs/core";
import { useEffect, useState } from "react";
import { Resplit } from 'react-resplit';
import useWebSocket, { ReadyState } from "react-use-websocket";

export default function App() {
const [spawnedProgram, setSpawnedProgram] = useState<string | null>(null);
const [handlers, setHandlers] = useState<Handler[]>([]);
const [selectedScope, setSelectedScope] = useState<ScopeId>("");
const [selectedHandler, setSelectedHandler] = useState<HandlerId>(-1);
const [handlerCode, setHandlerCode] = useState("");
const [draftedCode, setDraftedCode] = useState("");
const [addingTargets, setAddingTargets] = useState(false);
const [events, setEvents] = useState<Event[]>([]);
const [latestMatchingEventIndex, setLatestMatchingEventIndex] = useState<number | null>(null);
const [highlightedEventIndex, setHighlightedEventIndex] = useState<number | null>(null);
const [stagedItems, setStagedItems] = useState<StagedItem[]>([]);
const { sendJsonMessage, lastJsonMessage, readyState } = useWebSocket<TracerMessage>(
(import.meta.env.MODE === "development")
? "ws://localhost:1337"
: `ws://${window.location.host}`);

function handleHandlerSelection(id: HandlerId) {
setSelectedHandler(id);
setHighlightedEventIndex(null);
sendJsonMessage({ type: "handler:load", id });
}

function deploy(code: string) {
setHandlerCode(code);
setDraftedCode(code);
sendJsonMessage({ type: "handler:save", id: selectedHandler, code });
}

function handleEventActivation(id: HandlerId) {
const handler = handlers.find(h => h.id === id);
setSelectedScope(handler!.scope);
handleHandlerSelection(id);
}

function handleAddTargetsClose() {
setAddingTargets(false);
setStagedItems([]);
}

function handleAddTargetsQuery(scope: TraceSpecScope, query: string) {
if (query.length === 0 || query === "*") {
return;
}

const spec = [
["include", scope, query],
];
sendJsonMessage({ type: "targets:stage", profile: { spec } });
}

function handleAddTargetsCommit(id: StagedItemId | null) {
handleAddTargetsClose();
sendJsonMessage({ type: "targets:commit", id });
}

function handleRespawnRequest() {
sendJsonMessage({ type: "tracer:respawn" });
}

useEffect(() => {
if (lastJsonMessage === null) {
return;
}

switch (lastJsonMessage.type) {
case "tracer:sync":
setSpawnedProgram(lastJsonMessage.spawned_program);
setHandlers(lastJsonMessage.handlers);
break;
case "handlers:add":
setHandlers(handlers.concat(lastJsonMessage.handlers));
break;
case "handler:loaded": {
const { code } = lastJsonMessage;
setHandlerCode(code);
setDraftedCode(code);
break;
}
case "targets:staged":
setStagedItems(lastJsonMessage.items);
break;
case "events:add":
setEvents(events.concat(lastJsonMessage.events));
break;
default:
console.log("TODO:", lastJsonMessage);
break;
}

}, [lastJsonMessage]);

useEffect(() => {
for (let i = events.length - 1; i !== -1; i--) {
const event = events[i];
if (event[0] === selectedHandler) {
setLatestMatchingEventIndex(i);
return;
}
}
setLatestMatchingEventIndex(null);
}, [selectedHandler, events]);

const connectionError = (readyState === ReadyState.CLOSED)
const {
lostConnection,

spawnedProgram,
respawn,
mainModule,

handlers,
selectedScope,
selectScope,
selectedHandler,
selectHandler,
handlerCode,
draftedCode,
setDraftedCode,
deployCode,

events,
latestMatchingEventIndex,
highlightedEventIndex,
setHighlightedEventIndex,

addingTargets,
startAddingTargets,
finishAddingTargets,
stageItems,
stagedItems,
commitItems,
} = useModel();

const connectionError = lostConnection
? <Callout
title="Lost connection to frida-trace"
intent="danger"
/>
: null;

const eventView = (
<EventView
events={events}
highlightedIndex={highlightedEventIndex}
onActivate={selectHandler}
/>
);

const disassemblyView = (
<DisassemblyView mainModule={mainModule} />
);

return (
<>
<Resplit.Root className="app-content" direction="vertical">
Expand All @@ -140,13 +73,13 @@ export default function App() {
<HandlerList
handlers={handlers}
selectedScope={selectedScope}
onScopeSelect={scope => setSelectedScope(scope)}
onScopeSelect={selectScope}
selectedHandler={selectedHandler}
onHandlerSelect={handleHandlerSelection}
onHandlerSelect={selectHandler}
/>
<ButtonGroup className="target-actions" vertical={true} minimal={true} alignText="left">
<Button intent="success" icon="add" onClick={() => setAddingTargets(true)}>Add</Button>
{(spawnedProgram !== null) ? <Button intent="danger" icon="reset" onClick={handleRespawnRequest}>Respawn</Button> : null}
<Button intent="success" icon="add" onClick={startAddingTargets}>Add</Button>
{(spawnedProgram !== null) ? <Button intent="danger" icon="reset" onClick={respawn}>Respawn</Button> : null}
</ButtonGroup>
</section>
<section className="work-area">
Expand All @@ -155,7 +88,7 @@ export default function App() {
<Button
icon="rocket-slant"
disabled={draftedCode === handlerCode}
onClick={() => deploy(draftedCode)}
onClick={() => deployCode(draftedCode)}
>
Deploy
</Button>
Expand All @@ -171,63 +104,28 @@ export default function App() {
handlerId={selectedHandler}
handlerCode={handlerCode}
onChange={setDraftedCode}
onSave={deploy}
onSave={deployCode}
/>
</section>
</Resplit.Pane>
<Resplit.Splitter className="app-splitter" order={1} size="5px" />
<Resplit.Pane className="bottom-area" order={2} initialSize="0.3fr">
<EventView
events={events}
highlightedIndex={highlightedEventIndex}
onActivate={handleEventActivation}
/>
<Tabs className="bottom-tabs" defaultSelectedTabId="events" animate={false}>
<Tab id="events" title="Events" panel={eventView} panelClassName="bottom-tab-panel" />
<Tab id="disassembly" title="Disassembly" panel={disassemblyView} panelClassName="bottom-tab-panel" />
</Tabs>
</Resplit.Pane>
</Resplit.Root>
<AddTargetsDialog
isOpen={addingTargets}
stagedItems={stagedItems}
onClose={handleAddTargetsClose}
onQuery={handleAddTargetsQuery}
onCommit={handleAddTargetsCommit}
onClose={finishAddingTargets}
onQuery={stageItems}
onCommit={commitItems}
/>
<BlueprintProvider>
<div />
</BlueprintProvider>
</>
);
}

type TracerMessage =
| TracerSyncMessage
| HandlersAddMessage
| HandlerLoadedMessage
| TargetsStagedMessage
| EventsAddMessage
;

interface TracerSyncMessage {
type: "tracer:sync";
spawned_program: string | null;
handlers: Handler[];
}

interface HandlersAddMessage {
type: "handlers:add";
handlers: Handler[];
}

interface HandlerLoadedMessage {
type: "handler:loaded";
code: string;
}

interface TargetsStagedMessage {
type: "targets:staged";
items: StagedItem[];
}

interface EventsAddMessage {
type: "events:add";
events: Event[];
}
8 changes: 8 additions & 0 deletions apps/tracer/src/DisassemblyView.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.disassembly-view {
padding: 5px;
font-family: monospace;
font-size: 10px;
background-color: #1e1e1e;
color: #e4e4e4;
user-select: text;
}
Loading

0 comments on commit a270ecf

Please sign in to comment.