@@ -54,17 +54,6 @@ static bool IsLongIns(const uint8_t* data)
54
54
return data[0 ] == BPF_OPC_LDDW;
55
55
}
56
56
57
- static int16_t GetOffset (uint32_t x)
58
- {
59
- int16_t ret;
60
- if (x < 0x8000 ) {
61
- ret = (int16_t )x;
62
- } else {
63
- ret = (int16_t )(0x10000 - x);
64
- }
65
- return ret;
66
- }
67
-
68
57
class EBPFArchitecture : public Architecture {
69
58
private:
70
59
BNEndianness endian;
@@ -104,10 +93,10 @@ class EBPFArchitecture : public Architecture {
104
93
struct decomp_result res;
105
94
struct cs_insn * insn = &(res.insn );
106
95
107
- if (maxLen < 4 ) {
96
+ if (maxLen < 8 ) {
108
97
return false ;
109
98
}
110
- if (ebpf_decompose (data, 16 , addr, endian == LittleEndian, &res)) {
99
+ if (! ebpf_decompose (data, 16 , addr, endian == LittleEndian, &res)) {
111
100
goto beach;
112
101
}
113
102
@@ -130,8 +119,8 @@ class EBPFArchitecture : public Architecture {
130
119
result.AddBranch (FalseBranch, addr + 8 );
131
120
break ;
132
121
case BPF_INS_CALL:
133
- if (data[1 ] & 0xF0 == 0x10 ) {
134
- result.AddBranch (CallDestination, JumpDest (data, addr, endian == LittleEndian));
122
+ if (( data[1 ] & 0xF0 ) == 0x10 ) {
123
+ result.AddBranch (CallDestination, CallDest (data, addr, endian == LittleEndian));
135
124
} else {
136
125
result.AddBranch (SystemCall);
137
126
}
@@ -159,30 +148,34 @@ class EBPFArchitecture : public Architecture {
159
148
struct cs_insn * insn = &(res.insn );
160
149
struct cs_detail * detail = &(res.detail );
161
150
struct cs_bpf * bpf = &(detail->bpf );
162
- char buf[32 ];
163
151
size_t strlenMnem;
164
152
153
+ char buf[256 ];
154
+ #define FMT_I64 (x ) \
155
+ do { \
156
+ if ((x) >= 0 ) \
157
+ std::snprintf (buf, sizeof (buf), " +%#lx" , (x)); \
158
+ else \
159
+ std::snprintf (buf, sizeof (buf), " -%#lx" , -(x)); \
160
+ } while (0 )
161
+
165
162
if (len < 8 ) {
166
163
goto beach;
167
164
}
168
- if (ebpf_decompose (data, 16 , addr, endian == LittleEndian, &res)) {
165
+ if (! ebpf_decompose (data, 16 , addr, endian == LittleEndian, &res)) {
169
166
goto beach;
170
167
}
171
168
172
169
/* mnemonic */
173
170
result.emplace_back (InstructionToken, insn->mnemonic );
174
171
175
172
/* padding between mnemonic and operands */
176
- memset (buf, ' ' , 8 );
177
- strlenMnem = strlen (insn->mnemonic );
178
- if (strlenMnem < 8 )
179
- buf[8 - strlenMnem] = ' \0 ' ;
180
- else
181
- buf[1 ] = ' \0 ' ;
182
- result.emplace_back (TextToken, buf);
173
+ result.emplace_back (TextToken, std::string (10 - strlen (insn->mnemonic ), ' ' ));
183
174
184
175
if (insn->id == BPF_INS_CALL) {
185
- std::sprintf (buf, " %#lx" , bpf->operands [0 ].imm );
176
+ int64_t off = (int32_t )bpf->operands [0 ].imm ;
177
+ off = off * 8 + 8 ;
178
+ FMT_I64 (off);
186
179
result.emplace_back (PossibleAddressToken, buf, bpf->operands [0 ].imm , 8 );
187
180
len = 8 ;
188
181
return true ;
@@ -191,36 +184,29 @@ class EBPFArchitecture : public Architecture {
191
184
/* operands */
192
185
for (int i = 0 ; i < bpf->op_count ; ++i) {
193
186
struct cs_bpf_op * op = &(bpf->operands [i]);
194
- int16_t disp ;
187
+ int64_t val ;
195
188
196
189
switch (op->type ) {
197
190
case BPF_OP_REG:
198
191
result.emplace_back (RegisterToken, GetRegisterName (op->reg ));
199
192
break ;
200
193
case BPF_OP_IMM:
201
- // TODO special snowflake insn
202
- std::sprintf (buf, " %#lx " , op-> imm );
194
+ val = ( int32_t )bpf-> operands [ 0 ]. imm ;
195
+ FMT_I64 (val );
203
196
result.emplace_back (IntegerToken, buf, op->imm , 8 );
204
197
break ;
205
198
case BPF_OP_OFF:
206
- disp = GetOffset (op->off );
207
- if (disp >= 0 ) {
208
- std::sprintf (buf, " +%#x" , disp);
209
- } else {
210
- std::sprintf (buf, " -%#x" , -disp);
211
- }
212
- result.emplace_back (CodeRelativeAddressToken, buf, disp, 2 );
199
+ val = Int16SignExtend (op->off );
200
+ FMT_I64 (val);
201
+ result.emplace_back (CodeRelativeAddressToken, buf, val, 2 );
213
202
break ;
214
203
case BPF_OP_MEM:
215
204
result.emplace_back (TextToken, " [" );
205
+
216
206
result.emplace_back (RegisterToken, GetRegisterName (op->mem .base ));
217
- disp = GetOffset (op->mem .disp );
218
- if (disp >= 0 ) {
219
- std::sprintf (buf, " +%#x" , disp);
220
- } else {
221
- std::sprintf (buf, " -%#x" , -disp);
222
- }
223
- result.emplace_back (IntegerToken, buf, disp, 2 );
207
+ val = Int16SignExtend (op->mem .disp ) * 8 + 8 ;
208
+ FMT_I64 (val);
209
+ result.emplace_back (IntegerToken, buf, val, 2 );
224
210
225
211
result.emplace_back (TextToken, " ]" );
226
212
break ;
@@ -236,7 +222,7 @@ class EBPFArchitecture : public Architecture {
236
222
}
237
223
238
224
rc = true ;
239
- if (data[ 0 ] == BPF_OPC_LDDW ) {
225
+ if (IsLongIns ( data) ) {
240
226
len = 16 ;
241
227
} else {
242
228
len = 8 ;
@@ -256,13 +242,17 @@ class EBPFArchitecture : public Architecture {
256
242
if (len < 8 ) {
257
243
goto beach;
258
244
}
259
- if (ebpf_decompose (data, len, addr, endian == LittleEndian, &res)) {
245
+ if (! ebpf_decompose (data, len, addr, endian == LittleEndian, &res)) {
260
246
il.AddInstruction (il.Undefined ());
261
247
goto beach;
262
248
}
263
249
264
250
rc = GetLowLevelILForBPFInstruction (this , il, data, addr, &res, endian == LittleEndian);
265
- len = 8 ;
251
+ if (IsLongIns (data)) {
252
+ len = 16 ;
253
+ } else {
254
+ len = 8 ;
255
+ }
266
256
267
257
beach:
268
258
return rc;
@@ -634,7 +624,98 @@ class SolanaCallingConvention : public CallingConvention {
634
624
635
625
virtual uint32_t GetIntegerReturnValueRegister () override
636
626
{
637
- return PPC_REG_R0;
627
+ return BPF_REG_R0;
628
+ }
629
+ };
630
+
631
+ class EbpfElfRelocationHandler : public RelocationHandler {
632
+ public:
633
+ virtual bool ApplyRelocation (Ref<BinaryView> view, Ref<Architecture> arch, Ref<Relocation> reloc, uint8_t * dest, size_t len) override
634
+ {
635
+ auto info = reloc->GetInfo ();
636
+ uint64_t * dest64 = (uint64_t *)dest;
637
+ uint32_t * dest32 = (uint32_t *)dest;
638
+ uint16_t * dest16 = (uint16_t *)dest;
639
+ auto swap64 = [&arch](uint32_t x) { return (arch->GetEndianness () == LittleEndian) ? x : bswap64 (x); };
640
+ auto swap32 = [&arch](uint32_t x) { return (arch->GetEndianness () == LittleEndian) ? x : bswap32 (x); };
641
+ auto swap16 = [&arch](uint16_t x) { return (arch->GetEndianness () == LittleEndian) ? x : bswap16 (x); };
642
+ uint64_t target = reloc->GetTarget ();
643
+ std::vector<Ref<Section>> sections;
644
+ uint64_t rela_src;
645
+ switch (info.nativeType ) {
646
+ case R_BPF_64_64:
647
+ dest32[1 ] = swap32 ((uint32_t )((target + info.addend ) & 0xffffffff ));
648
+ dest32[3 ] = swap32 ((uint32_t )((target + info.addend ) >> 32 ));
649
+ break ;
650
+ case R_BPF_64_ABS64:
651
+ dest64[0 ] = swap64 (target + info.addend );
652
+ break ;
653
+ case R_BPF_64_ABS32:
654
+ case R_BPF_64_NODYLD32:
655
+ dest64[0 ] = swap32 ((uint32_t )(target + info.addend ));
656
+ break ;
657
+ case R_BPF_64_RELATIVE:
658
+ // Super weird reloc
659
+ sections = view->GetSectionsAt (reloc->GetAddress ());
660
+ if (!sections.empty () && sections[0 ]->GetName () == " .text" ) {
661
+ rela_src = 0 ;
662
+ rela_src = swap32 (dest32[1 ]) | ((uint64_t )(swap32 (dest32[3 ])) << 32 );
663
+ // wtf?
664
+ if (rela_src < 0x100000000 ) {
665
+ rela_src += 0x100000000 ;
666
+ }
667
+ dest32[1 ] = swap32 ((uint32_t )((rela_src) & 0xffffffff ));
668
+ dest32[3 ] = swap32 ((uint32_t )((rela_src) >> 32 ));
669
+ } else {
670
+ // i give up
671
+ }
672
+ sections.clear ();
673
+ break ;
674
+ case R_BPF_64_32:
675
+ // TODO This isn't documented as pc-rel, but BPF_INS_CALL takes pc-rel immediate
676
+ dest32[1 ] = swap32 ((uint32_t )((target + info.addend - reloc->GetAddress ()) / 8 - 1 ));
677
+ break ;
678
+ }
679
+ return true ;
680
+ }
681
+
682
+ virtual bool GetRelocationInfo (Ref<BinaryView> view, Ref<Architecture> arch, std::vector<BNRelocationInfo>& result) override
683
+ {
684
+ std::set<uint64_t > relocTypes;
685
+ for (auto & reloc : result) {
686
+ reloc.type = StandardRelocationType;
687
+ reloc.size = 8 ;
688
+ reloc.pcRelative = false ;
689
+ reloc.dataRelocation = false ;
690
+ switch (reloc.nativeType ) {
691
+ case R_BPF_NONE:
692
+ reloc.type = IgnoredRelocation;
693
+ break ;
694
+ case R_BPF_64_64:
695
+ break ;
696
+ case R_BPF_64_ABS64:
697
+ reloc.dataRelocation = true ;
698
+ break ;
699
+ case R_BPF_64_ABS32:
700
+ case R_BPF_64_NODYLD32:
701
+ reloc.dataRelocation = true ;
702
+ reloc.size = 4 ;
703
+ break ;
704
+ case R_BPF_64_RELATIVE:
705
+ reloc.pcRelative = true ; // not really??
706
+ break ;
707
+ case R_BPF_64_32:
708
+ reloc.size = 4 ;
709
+ break ;
710
+ default :
711
+ reloc.type = UnhandledRelocation;
712
+ relocTypes.insert (reloc.nativeType );
713
+ break ;
714
+ }
715
+ }
716
+ for (auto & reloc : relocTypes)
717
+ LogWarn (" Unsupported ELF relocation type: %s" , GetRelocationString ((ElfBpfRelocationType)reloc));
718
+ return true ;
638
719
}
639
720
};
640
721
@@ -670,6 +751,9 @@ BINARYNINJAPLUGIN bool CorePluginInit()
670
751
ebpf_le->RegisterCallingConvention (conv);
671
752
ebpf_le->SetDefaultCallingConvention (conv);
672
753
754
+ ebpf_le->RegisterRelocationHandler (" ELF" , new EbpfElfRelocationHandler ());
755
+ ebpf_be->RegisterRelocationHandler (" ELF" , new EbpfElfRelocationHandler ());
756
+
673
757
return true ;
674
758
}
675
759
}
0 commit comments