unidecompiler-plugin-dotnet-cli 0.1.1__tar.gz → 0.1.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 (17) hide show
  1. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/PKG-INFO +2 -2
  2. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/pyproject.toml +2 -2
  3. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/src/unidecompiler_plugin_dotnet_cli/assembly.py +16 -4
  4. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/src/unidecompiler_plugin_dotnet_cli/lifter.py +55 -37
  5. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/src/unidecompiler_plugin_dotnet_cli/simulation.py +6 -1
  6. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/src/unidecompiler_plugin_dotnet_cli.egg-info/PKG-INFO +2 -2
  7. unidecompiler_plugin_dotnet_cli-0.1.3/src/unidecompiler_plugin_dotnet_cli.egg-info/requires.txt +2 -0
  8. unidecompiler_plugin_dotnet_cli-0.1.1/src/unidecompiler_plugin_dotnet_cli.egg-info/requires.txt +0 -2
  9. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/README.md +0 -0
  10. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/setup.cfg +0 -0
  11. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/src/unidecompiler_plugin_dotnet_cli/__init__.py +0 -0
  12. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/src/unidecompiler_plugin_dotnet_cli/plugin.py +0 -0
  13. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/src/unidecompiler_plugin_dotnet_cli/support.py +0 -0
  14. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/src/unidecompiler_plugin_dotnet_cli.egg-info/SOURCES.txt +0 -0
  15. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/src/unidecompiler_plugin_dotnet_cli.egg-info/dependency_links.txt +0 -0
  16. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/src/unidecompiler_plugin_dotnet_cli.egg-info/entry_points.txt +0 -0
  17. {unidecompiler_plugin_dotnet_cli-0.1.1 → unidecompiler_plugin_dotnet_cli-0.1.3}/src/unidecompiler_plugin_dotnet_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unidecompiler-plugin-dotnet-cli
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: .NET CLI assembly frontend plugin for unidecompiler
5
5
  Author-email: Wker <1670133844@qq.com>
6
6
  License-Expression: AGPL-3.0-or-later
@@ -9,7 +9,7 @@ Project-URL: Repository, https://github.com/Wker666/unidecompiler
9
9
  Project-URL: Issues, https://github.com/Wker666/unidecompiler/issues
10
10
  Requires-Python: >=3.11
11
11
  Description-Content-Type: text/markdown
12
- Requires-Dist: unidecompiler<0.2.0,>=0.1.1
12
+ Requires-Dist: unidecompiler<0.2.0,>=0.1.9
13
13
  Requires-Dist: dnfile<1,>=0.15
14
14
 
15
15
  # unidecompiler-plugin-dotnet-cli
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "unidecompiler-plugin-dotnet-cli"
7
- version = "0.1.1"
7
+ version = "0.1.3"
8
8
  description = ".NET CLI assembly frontend plugin for unidecompiler"
9
9
  readme = "README.md"
10
10
  license = "AGPL-3.0-or-later"
11
11
  authors = [{ name = "Wker", email = "1670133844@qq.com" }]
12
12
  requires-python = ">=3.11"
13
- dependencies = ["unidecompiler>=0.1.1,<0.2.0", "dnfile>=0.15,<1"]
13
+ dependencies = ["unidecompiler>=0.1.9,<0.2.0", "dnfile>=0.15,<1"]
14
14
 
15
15
  [project.urls]
16
16
  Homepage = "https://github.com/Wker666/unidecompiler"
@@ -26,6 +26,8 @@ class DotNetInstruction:
26
26
  arg_count: int | None = None
27
27
  returns_void: bool | None = None
28
28
  is_static: bool | None = None
29
+ artifact_offset: int | None = None
30
+ size: int | None = None
29
31
 
30
32
 
31
33
  @dataclass(frozen=True)
@@ -132,7 +134,7 @@ def _method_listing(pe, row_index: int, row) -> DotNetMethodListing:
132
134
  param_count=_signature_param_count(row.Signature),
133
135
  max_stack=None if body is None else body.max_stack,
134
136
  code_size=0 if body is None else len(body.code),
135
- instructions=() if body is None else _decode_il(pe, body.code),
137
+ instructions=() if body is None else _decode_il(pe, body.code, body.artifact_offset),
136
138
  )
137
139
 
138
140
 
@@ -140,6 +142,7 @@ def _method_listing(pe, row_index: int, row) -> DotNetMethodListing:
140
142
  class _MethodBody:
141
143
  max_stack: int
142
144
  code: bytes
145
+ artifact_offset: int | None
143
146
 
144
147
 
145
148
  def _read_method_body(pe, rva: int) -> _MethodBody | None:
@@ -150,7 +153,7 @@ def _read_method_body(pe, rva: int) -> _MethodBody | None:
150
153
  kind = first & 0x3
151
154
  if kind == 0x2:
152
155
  code_size = first >> 2
153
- return _MethodBody(max_stack=8, code=pe.get_data(rva + 1, code_size))
156
+ return _MethodBody(max_stack=8, code=pe.get_data(rva + 1, code_size), artifact_offset=_artifact_offset(pe, rva + 1))
154
157
  if kind == 0x3:
155
158
  header = pe.get_data(rva, 12)
156
159
  if len(header) < 12:
@@ -159,7 +162,7 @@ def _read_method_body(pe, rva: int) -> _MethodBody | None:
159
162
  header_size = (_flags_size >> 12) * 4
160
163
  if header_size < 12:
161
164
  return None
162
- return _MethodBody(max_stack=max_stack, code=pe.get_data(rva + header_size, code_size))
165
+ return _MethodBody(max_stack=max_stack, code=pe.get_data(rva + header_size, code_size), artifact_offset=_artifact_offset(pe, rva + header_size))
163
166
  return None
164
167
 
165
168
 
@@ -428,7 +431,14 @@ _TWO_BYTE_OPCODES = {
428
431
  }
429
432
 
430
433
 
431
- def _decode_il(pe, code: bytes) -> tuple[DotNetInstruction, ...]:
434
+ def _artifact_offset(pe, rva: int) -> int | None:
435
+ try:
436
+ return int(pe.get_offset_from_rva(rva))
437
+ except Exception:
438
+ return None
439
+
440
+
441
+ def _decode_il(pe, code: bytes, artifact_offset: int | None = None) -> tuple[DotNetInstruction, ...]:
432
442
  instructions: list[DotNetInstruction] = []
433
443
  offset = 0
434
444
  while offset < len(code):
@@ -454,6 +464,8 @@ def _decode_il(pe, code: bytes) -> tuple[DotNetInstruction, ...]:
454
464
  arg_count=operand.arg_count,
455
465
  returns_void=operand.returns_void,
456
466
  is_static=operand.is_static,
467
+ artifact_offset=None if artifact_offset is None else artifact_offset + start,
468
+ size=offset - start,
457
469
  )
458
470
  )
459
471
  return tuple(instructions)
@@ -6,6 +6,7 @@ from unidecompiler.core.effects import (
6
6
  BuildCall,
7
7
  CallTopAs,
8
8
  DuplicateTop,
9
+ Emit,
9
10
  InvokeMember,
10
11
  LoadIndirect,
11
12
  LoadAttr,
@@ -15,6 +16,7 @@ from unidecompiler.core.effects import (
15
16
  Pop,
16
17
  Push,
17
18
  RaiseTop,
19
+ ReraiseTop,
18
20
  ReturnTop,
19
21
  StoreAttr,
20
22
  StoreIndirect,
@@ -23,13 +25,14 @@ from unidecompiler.core.effects import (
23
25
  StoreStaticMember,
24
26
  UnknownOpcode,
25
27
  )
26
- from unidecompiler.core.ir import BinaryOp, Const, Expr, Global, IndirectRef, SourceRef, Var
28
+ from unidecompiler.core.ir import BinaryOp, Const, Expr, Global, IndirectRef, SourceRef, Unsupported, Var
27
29
  from unidecompiler.core.vm_bytecode import VMBytecodeStep
28
30
  from unidecompiler.core.vm_effect_table import VMEffectRule, VMEffectTable
29
31
  from unidecompiler.core.vm_function import VMFunctionSpec, lift_steps, lift_vm_step_function, recover_vm_function
30
32
  from unidecompiler.core.vm_hints import VMHint
31
33
  from unidecompiler.core.vm_module import assemble_vm_module
32
34
  from unidecompiler.core.vm_operands import VMDecodedInstruction, VMOperand
35
+ from unidecompiler.provenance import ByteRange
33
36
  from unidecompiler.core.vm_region import (
34
37
  VMLinearState,
35
38
  VMRegionOpcodeClasses,
@@ -151,38 +154,7 @@ IGNORED_OPS = {
151
154
  "volatile.",
152
155
  "unaligned.",
153
156
  "prefix",
154
- "castclass",
155
- "box",
156
- "unbox",
157
- "unbox.any",
158
- "conv.i",
159
- "conv.i1",
160
- "conv.i2",
161
- "conv.i4",
162
- "conv.i8",
163
- "conv.u",
164
- "conv.u1",
165
- "conv.u2",
166
- "conv.u4",
167
- "conv.u8",
168
- "conv.r4",
169
- "conv.r8",
170
- "conv.r.un",
171
- "conv.ovf.i",
172
- "conv.ovf.i.un",
173
- "conv.ovf.i1.un",
174
- "conv.ovf.i2.un",
175
- "conv.ovf.i4.un",
176
- "conv.ovf.i8.un",
177
- "conv.ovf.u",
178
- "conv.ovf.u.un",
179
- "conv.ovf.u1.un",
180
- "conv.ovf.u2.un",
181
- "conv.ovf.u4.un",
182
- "conv.ovf.u8.un",
183
157
  "endfinally",
184
- "endfilter",
185
- "rethrow",
186
158
  *CONTROL_OPS,
187
159
  }
188
160
 
@@ -249,6 +221,13 @@ def _dotnet_load_local_effect(method: DotNetMethodListing, instruction: DotNetIn
249
221
  if index is None:
250
222
  return None
251
223
  name = _local_name(method, index)
224
+ if instruction.opcode.startswith("ldloca"):
225
+ return (
226
+ Push(
227
+ source=source,
228
+ value=IndirectRef(source=source, target=Var(name=name, source=source)),
229
+ ),
230
+ )
252
231
  return (LoadLocal(source=source, name=name, fallback=Var(name=name, source=source)),)
253
232
 
254
233
 
@@ -324,6 +303,36 @@ def _dotnet_call(_method: DotNetMethodListing, instruction: DotNetInstruction, s
324
303
  )
325
304
 
326
305
 
306
+ def _dotnet_operation_call(arg_count: int, *, returns: int = 0):
307
+ def factory(
308
+ _method: DotNetMethodListing,
309
+ instruction: DotNetInstruction,
310
+ source: SourceRef,
311
+ ) -> tuple:
312
+ suffix = f"<{instruction.operands}>" if instruction.operands else ""
313
+ return (
314
+ BuildCall(
315
+ source=source,
316
+ callee=Global(name=f"{instruction.opcode}{suffix}", source=source),
317
+ arg_count=arg_count,
318
+ returns=returns,
319
+ ),
320
+ )
321
+
322
+ return factory
323
+
324
+
325
+ def _dotnet_unary_operation(_method, instruction, source: SourceRef) -> tuple:
326
+ # Keep the CLI operation name neutral and readable. Operand metadata is
327
+ # already retained on the decoded instruction; embedding the Python tuple
328
+ # representation in the callee name prevents generic intrinsic handling.
329
+ return (CallTopAs(source=source, callee_name=instruction.opcode),)
330
+
331
+
332
+ def _dotnet_unsupported_operation(_method, instruction, source: SourceRef) -> tuple:
333
+ return (Emit(source=source, statement=Unsupported(source=source, message="unsupported CLI control operation", detail=instruction.opcode, raw=(_dotnet_raw_instruction_line(instruction),))),)
334
+
335
+
327
336
  DOTNET_EFFECT_TABLE = VMEffectTable(
328
337
  opcode_attr="opcode",
329
338
  ignored=frozenset(IGNORED_OPS),
@@ -331,6 +340,12 @@ DOTNET_EFFECT_TABLE = VMEffectTable(
331
340
  **{opcode: _dotnet_binary(opcode, op) for opcode, op in BINARY_OPS.items()},
332
341
  **{opcode: _dotnet_compare(opcode, op) for opcode, op in COMPARE_OPS.items()},
333
342
  "ldnull": lambda _method, _instruction, source: (Push(source=source, value=Const(value=None, source=source)),),
343
+ **{opcode: _dotnet_unary_operation for opcode in {
344
+ "castclass", "box", "unbox", "unbox.any", "conv.i", "conv.i1", "conv.i2", "conv.i4", "conv.i8",
345
+ "conv.u", "conv.u1", "conv.u2", "conv.u4", "conv.u8", "conv.r4", "conv.r8", "conv.r.un",
346
+ "conv.ovf.i", "conv.ovf.i.un", "conv.ovf.i1.un", "conv.ovf.i2.un", "conv.ovf.i4.un", "conv.ovf.i8.un",
347
+ "conv.ovf.u", "conv.ovf.u.un", "conv.ovf.u1.un", "conv.ovf.u2.un", "conv.ovf.u4.un", "conv.ovf.u8.un",
348
+ }},
334
349
  "dup": lambda _method, instruction, source: (DuplicateTop(source=source, materialized_name=f"local_stack_{instruction.offset}"),),
335
350
  "pop": lambda _method, _instruction, source: (Pop(source=source, count=1, emit_calls=True),),
336
351
  "neg": lambda _method, _instruction, source: (CallTopAs(source=source, callee_name="neg"),),
@@ -341,12 +356,12 @@ DOTNET_EFFECT_TABLE = VMEffectTable(
341
356
  "jmp": _dotnet_call,
342
357
  "ldftn": lambda _method, instruction, source: (Push(source=source, value=Global(name=_member_token_name(instruction.operands), source=source)),),
343
358
  "ldvirtftn": lambda _method, instruction, source: (Push(source=source, value=Global(name=_member_token_name(instruction.operands), source=source)),),
344
- "initobj": lambda _method, _instruction, source: (Pop(source=source, count=1, allow_missing=True),),
359
+ "initobj": _dotnet_operation_call(1),
345
360
  "arglist": lambda _method, _instruction, source: (Push(source=source, value=Global(name="arglist", source=source)),),
346
361
  "ckfinite": lambda _method, _instruction, source: (CallTopAs(source=source, callee_name="check_finite"),),
347
- "cpblk": lambda _method, _instruction, source: (Pop(source=source, count=3, allow_missing=True),),
348
- "cpobj": lambda _method, _instruction, source: (Pop(source=source, count=2, allow_missing=True),),
349
- "initblk": lambda _method, _instruction, source: (Pop(source=source, count=3, allow_missing=True),),
362
+ "cpblk": _dotnet_operation_call(3),
363
+ "cpobj": _dotnet_operation_call(2),
364
+ "initblk": _dotnet_operation_call(3),
350
365
  "localloc": lambda _method, _instruction, source: (BuildCall(source=source, callee=Global(name="localloc", source=source), arg_count=1),),
351
366
  "mkrefany": lambda _method, instruction, source: (BuildCall(source=source, callee=Global(name=f"mkrefany<{instruction.operands or 'type'}>", source=source), arg_count=1),),
352
367
  "refanytype": lambda _method, _instruction, source: (CallTopAs(source=source, callee_name="refanytype"),),
@@ -355,7 +370,7 @@ DOTNET_EFFECT_TABLE = VMEffectTable(
355
370
  "ldstr": lambda _method, instruction, source: (Push(source=source, value=Const(value=instruction.operands, source=source)),),
356
371
  "ldtoken": lambda _method, instruction, source: (Push(source=source, value=Global(name=instruction.operands, source=source)),),
357
372
  "isinst": lambda _method, instruction, source: (BuildCall(source=source, callee=Global(name="instanceof", source=source), arg_count=1, returns=1),),
358
- "ldobj": lambda _method, instruction, source: (Pop(source=source, count=1, allow_missing=True), Push(source=source, value=Global(name=_member_token_name(instruction.operands), source=source))),
373
+ "ldobj": _dotnet_operation_call(1, returns=1),
359
374
  "ldfld": lambda _method, instruction, source: (LoadAttr(source=source, attr=_member_name(instruction)),),
360
375
  "ldflda": lambda _method, instruction, source: (LoadAttr(source=source, attr=_member_name(instruction)),),
361
376
  "stfld": lambda _method, instruction, source: (StoreAttr(source=source, attr=_member_name(instruction)),),
@@ -371,6 +386,8 @@ DOTNET_EFFECT_TABLE = VMEffectTable(
371
386
  "ldlen": lambda _method, _instruction, source: (LoadAttr(source=source, attr="length"),),
372
387
  "newarr": lambda _method, instruction, source: (BuildArrayCall(source=source, kind=instruction.operands or "array"),),
373
388
  "throw": lambda _method, _instruction, source: (RaiseTop(source=source),),
389
+ "rethrow": lambda _method, _instruction, source: (ReraiseTop(source=source),),
390
+ "endfilter": _dotnet_unsupported_operation,
374
391
  "ret": lambda _method, _instruction, source: (ReturnTop(source=source, empty_is_void=True),),
375
392
  },
376
393
  rules=(
@@ -551,6 +568,7 @@ def _dotnet_decoded_instruction(instruction: DotNetInstruction, source: SourceRe
551
568
  source=source,
552
569
  operands=operands,
553
570
  raw=_dotnet_raw_instruction_line(instruction),
571
+ artifact_range=(None if instruction.artifact_offset is None or instruction.size is None else ByteRange(instruction.artifact_offset, instruction.size)),
554
572
  )
555
573
 
556
574
 
@@ -19,7 +19,12 @@ class DotNetSimulationAdapter:
19
19
  return ResolvedFunction(matches[0], context=context, identifier=query)
20
20
 
21
21
  def resolve_global(self, name, context):
22
- from unidecompiler_simulator import NotHandled, ResolvedFunction
22
+ from unidecompiler_simulator import IntrinsicCall, NotHandled, ResolvedFunction
23
+
24
+ # Conversion and unary operation names emitted by the generic lifter
25
+ # are pure value intrinsics, not methods in the lifted module.
26
+ if name.startswith(("conv.", "castclass", "box", "unbox", "neg", "bitnot", "check_finite", "refanytype")):
27
+ return IntrinsicCall(name)
23
28
 
24
29
  if not isinstance(context, dict):
25
30
  return NotHandled
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unidecompiler-plugin-dotnet-cli
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: .NET CLI assembly frontend plugin for unidecompiler
5
5
  Author-email: Wker <1670133844@qq.com>
6
6
  License-Expression: AGPL-3.0-or-later
@@ -9,7 +9,7 @@ Project-URL: Repository, https://github.com/Wker666/unidecompiler
9
9
  Project-URL: Issues, https://github.com/Wker666/unidecompiler/issues
10
10
  Requires-Python: >=3.11
11
11
  Description-Content-Type: text/markdown
12
- Requires-Dist: unidecompiler<0.2.0,>=0.1.1
12
+ Requires-Dist: unidecompiler<0.2.0,>=0.1.9
13
13
  Requires-Dist: dnfile<1,>=0.15
14
14
 
15
15
  # unidecompiler-plugin-dotnet-cli
@@ -0,0 +1,2 @@
1
+ unidecompiler<0.2.0,>=0.1.9
2
+ dnfile<1,>=0.15
@@ -1,2 +0,0 @@
1
- unidecompiler<0.2.0,>=0.1.1
2
- dnfile<1,>=0.15