44
55#include " SharedCacheUINotifications.h"
66#include < sharedcacheapi.h>
7+ #include " mediumlevelilinstruction.h"
78#include " ui/sidebar.h"
89#include " ui/linearview.h"
910#include " ui/viewframe.h"
@@ -15,6 +16,58 @@ using namespace SharedCacheAPI;
1516
1617UINotifications* UINotifications::m_instance = nullptr ;
1718
19+ // Resolve a stub function at `addr` to the constant target of its jump or tail call. Stub functions
20+ // are identified by the `j_` symbol prefix that the shared cache workflow applies when renaming them.
21+ static std::optional<uint64_t > ResolveStubTarget (BinaryView& view, uint64_t addr)
22+ {
23+ auto symbol = view.GetSymbolByAddress (addr);
24+ if (!symbol || symbol->GetShortName ().rfind (" j_" , 0 ) != 0 )
25+ return std::nullopt ;
26+
27+ auto func = view.GetAnalysisFunction (view.GetDefaultPlatform (), addr);
28+ if (!func)
29+ return std::nullopt ;
30+
31+ // Skip any function that is very clearly not a stub (not a single basic block with only a few instructions).
32+ const auto blocks = func->GetBasicBlocks ();
33+ constexpr uint64_t maxStubLength = 0x20 ;
34+ if (blocks.size () != 1 || blocks[0 ]->GetLength () > maxStubLength)
35+ return std::nullopt ;
36+
37+ auto mlil = func->GetMediumLevelIL ();
38+ if (!mlil)
39+ return std::nullopt ;
40+
41+ for (const auto & block : mlil->GetBasicBlocks ())
42+ {
43+ for (size_t i = block->GetStart (), end = block->GetEnd (); i < end; ++i)
44+ {
45+ const auto instr = mlil->GetInstruction (i);
46+ if (instr.operation != MLIL_JUMP && instr.operation != MLIL_TAILCALL )
47+ continue ;
48+ const auto dest = instr.GetDestExpr ();
49+ if (dest.operation != MLIL_CONST_PTR && dest.operation != MLIL_CONST )
50+ continue ;
51+ return dest.GetConstant ();
52+ }
53+ }
54+
55+ return std::nullopt ;
56+ }
57+
58+ // The address a token-based load action should operate on. A stub function's address is in an
59+ // already-loaded image, so resolve it to its target and offer to load what the stub jumps to.
60+ static uint64_t TokenAddress (const UIActionContext& ctx)
61+ {
62+ uint64_t addr = ctx.token .token .value ;
63+ if (!ctx.binaryView ->GetSectionsAt (addr).empty ())
64+ {
65+ if (auto target = ResolveStubTarget (*ctx.binaryView , addr))
66+ return *target;
67+ }
68+ return addr;
69+ }
70+
1871void UINotifications::init ()
1972{
2073 m_instance = new UINotifications;
@@ -95,19 +148,21 @@ void UINotifications::OnViewChange(UIContext* context, ViewFrame* frame, const Q
95148 };
96149
97150 auto loadRegionTokenAction = [](const UIActionContext& ctx) {
151+ uint64_t addr = TokenAddress (ctx);
98152 BackgroundThread::create (ctx.context ->mainWindow ())
99- ->thenBackground ([ctx](){ loadRegionAtAddr (*ctx.binaryView , ctx. token . token . value ); })
153+ ->thenBackground ([ctx, addr ](){ loadRegionAtAddr (*ctx.binaryView , addr ); })
100154 ->start ();
101155 };
102156
103157 auto loadImageTokenAction = [](const UIActionContext& ctx) {
158+ uint64_t addr = TokenAddress (ctx);
104159 BackgroundThread::create (ctx.context ->mainWindow ())
105- ->thenBackground ([ctx](){ loadImageAtAddr (*ctx.binaryView , ctx. token . token . value ); })
160+ ->thenBackground ([ctx, addr ](){ loadImageAtAddr (*ctx.binaryView , addr ); })
106161 ->start ();
107162 };
108163
109164 auto isValidUnloadedRegionAction = [](const UIActionContext& ctx) {
110- uint64_t addr = ctx. token . token . value ;
165+ uint64_t addr = TokenAddress ( ctx) ;
111166 // Check if the region is already loaded in the view.
112167 if (!ctx.binaryView ->GetSectionsAt (addr).empty ())
113168 return false ;
@@ -118,7 +173,7 @@ void UINotifications::OnViewChange(UIContext* context, ViewFrame* frame, const Q
118173 };
119174
120175 auto isValidUnloadedImageAction = [](const UIActionContext& ctx) {
121- uint64_t addr = ctx. token . token . value ;
176+ uint64_t addr = TokenAddress ( ctx) ;
122177 // Check if the image is already loaded in the view.
123178 if (!ctx.binaryView ->GetSectionsAt (addr).empty ())
124179 return false ;
@@ -139,7 +194,7 @@ void UINotifications::OnViewChange(UIContext* context, ViewFrame* frame, const Q
139194 auto controller = SharedCacheController::GetController (*ctx.binaryView );
140195 if (!controller)
141196 return QString (" NO CONTROLLER" );
142- uint64_t addr = ctx. token . token . value ;
197+ uint64_t addr = TokenAddress ( ctx) ;
143198 auto region = controller->GetRegionContaining (addr);
144199 if (!region)
145200 return QString (" NO REGION" );
@@ -150,7 +205,7 @@ void UINotifications::OnViewChange(UIContext* context, ViewFrame* frame, const Q
150205 auto controller = SharedCacheController::GetController (*ctx.binaryView );
151206 if (!controller)
152207 return QString (" NO CONTROLLER" );
153- uint64_t addr = ctx. token . token . value ;
208+ uint64_t addr = TokenAddress ( ctx) ;
154209 auto image = controller->GetImageContaining (addr);
155210 if (!image)
156211 return QString (" NO IMAGE" );
0 commit comments