Exetools  

Go Back   Exetools > General > General Discussion

Notices

Reply
 
Thread Tools Display Modes
  #1  
Old 02-26-2019, 13:05
WhoCares's Avatar
WhoCares WhoCares is offline
who cares
 
Join Date: Jan 2002
Location: Here
Posts: 335
Rept. Given: 7
Rept. Rcvd 11 Times in 9 Posts
Thanks Given: 15
Thanks Rcvd at 56 Times in 26 Posts
WhoCares Reputation: 11
Reflector gets wrong decompiling result?

same dll and same function body, different decompiling results for Reflector, dotPeek, dnSpy(all are latest versions).

Reflector
Code:
    private uint e(byte[] a, ref int b)
    {
        b += 4;
        return BitConverter.ToUInt32(a, b);
    }
dotPeek, dnSpy
Code:
  private uint e(byte[] a, ref int b)
  {
    int uint32 = (int) BitConverter.ToUInt32(a, b);
    b += 4;
    return (uint) uint32;
  }
IL of function body
Code:
  .method private hidebysig instance unsigned int32
    e(
      unsigned int8[] a,
      int32& b
    ) cil managed
  {
    .maxstack 8

    IL_0000: ldarg.1      // a
    IL_0001: ldarg.2      // b
    IL_0002: ldind.i4
    IL_0003: call         unsigned int32 [mscorlib]System.BitConverter::ToUInt32(unsigned int8[], int32)
    IL_0008: ldarg.2      // b
    IL_0009: ldarg.2      // b
    IL_000a: ldind.i4
    IL_000b: ldc.i4.4
    IL_000c: add
    IL_000d: stind.i4
    IL_000e: ret

  } // end of method e
__________________
AKA Solomon/blowfish.
Reply With Quote
The Following User Says Thank You to WhoCares For This Useful Post:
chants (02-26-2019)
  #2  
Old 02-26-2019, 13:16
chants chants is online now
Family
 
Join Date: Jul 2016
Posts: 447
Rept. Given: 1
Rept. Rcvd 30 Times in 18 Posts
Thanks Given: 357
Thanks Rcvd at 701 Times in 326 Posts
chants Reputation: 30
Reflector has bad dataflow optimization semantics now apparently in ref arg cases
Reply With Quote
  #3  
Old 02-26-2019, 16:32
deepzero's Avatar
deepzero deepzero is offline
VIP
 
Join Date: Mar 2010
Location: Europe
Posts: 215
Rept. Given: 99
Rept. Rcvd 60 Times in 38 Posts
Thanks Given: 83
Thanks Rcvd at 95 Times in 50 Posts
deepzero Reputation: 60
Nah, Reflector is the one who got it right.
Seems the others got thoroughly confused there ... int uint32 = ..
Reply With Quote
The Following User Says Thank You to deepzero For This Useful Post:
chants (02-27-2019)
  #4  
Old 02-27-2019, 00:02
chants chants is online now
Family
 
Join Date: Jul 2016
Posts: 447
Rept. Given: 1
Rept. Rcvd 30 Times in 18 Posts
Thanks Given: 357
Thanks Rcvd at 701 Times in 326 Posts
chants Reputation: 30
Yup I meant other way around, Reflector right
Reply With Quote
  #5  
Old 02-27-2019, 10:40
WhoCares's Avatar
WhoCares WhoCares is offline
who cares
 
Join Date: Jan 2002
Location: Here
Posts: 335
Rept. Given: 7
Rept. Rcvd 11 Times in 9 Posts
Thanks Given: 15
Thanks Rcvd at 56 Times in 26 Posts
WhoCares Reputation: 11
"b +=4;", should appear first or last?
__________________
AKA Solomon/blowfish.
Reply With Quote
  #6  
Old 02-27-2019, 16:09
deepzero's Avatar
deepzero deepzero is offline
VIP
 
Join Date: Mar 2010
Location: Europe
Posts: 215
Rept. Given: 99
Rept. Rcvd 60 Times in 38 Posts
Thanks Given: 83
Thanks Rcvd at 95 Times in 50 Posts
deepzero Reputation: 60
First.

Code:
    IL_0000: ldarg.1      // load a
    IL_0001: ldarg.2      // load b (which is a reference)
    IL_0002: ldind.i4      //dereference b (bc it is is reference: int&)
    IL_0003: call         BitConverter::ToUInt() //call and put result on stack
then

Code:
    IL_0008: ldarg.2      // load b on stack for later use
    IL_0009: ldarg.2      // load b
    IL_000a: ldind.i4      //dereference it
    IL_000b: ldc.i4.4      //load interger-constant "4" to stack
    IL_000c: add           //add the values of b and "4" and put the result on the stack
SO now the stack looks like this:


Code:
<value: result of b+4>
<reference: b> (was loaded at IL_0008)
<value: return value of the BitConverter call>

Then the last piece of the puzzle:

Code:
    IL_000d: stind.i4   //store the result of  "b+4" in b
There now is just one entry on the stack:

Code:
<value: return value of the BitConverter call>
and finally return that last entry:

Code:
    IL_000e: ret


So in conclusion the method does two things: 1) b += 4 and 2) return BitConverter(). So reflector is right and the others are wrong. You should file a bug report.


A more literal decompilation would be:


Code:
    private uint e(byte[] a, ref int b)
    {
        uint32 tmp = BitConverter.ToUInt32(a, b);
        b += 4;
        return tmp;
    }
But you can trivially optimize that by eliminating the tmp variable.
Reply With Quote
The Following 2 Users Say Thank You to deepzero For This Useful Post:
tonyweb (03-02-2019), WhoCares (02-27-2019)
  #7  
Old 02-27-2019, 21:32
WhoCares's Avatar
WhoCares WhoCares is offline
who cares
 
Join Date: Jan 2002
Location: Here
Posts: 335
Rept. Given: 7
Rept. Rcvd 11 Times in 9 Posts
Thanks Given: 15
Thanks Rcvd at 56 Times in 26 Posts
WhoCares Reputation: 11
ok, I understand those IL instructions now. thanks!

Besides ECMA specification, MS also documents the instructions:
https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.ldind_i4?view=netframework-4.7.2
__________________
AKA Solomon/blowfish.
Reply With Quote
  #8  
Old 02-28-2019, 04:51
chants chants is online now
Family
 
Join Date: Jul 2016
Posts: 447
Rept. Given: 1
Rept. Rcvd 30 Times in 18 Posts
Thanks Given: 357
Thanks Rcvd at 701 Times in 326 Posts
chants Reputation: 30
However, if the referenced value (b) is unused, in all caller contexts which invoke this function, then theoretically
Quote:
b += 4
can be optimized out. Of course with reflection or exporting that would be somewhat impossible to deduce but these sorts of assumptions are more complicated issues even the compiler has to make decisions about and usually documented vaguely somewhere as to what guarantees are provided.
Reply With Quote
  #9  
Old 02-28-2019, 11:30
WhoCares's Avatar
WhoCares WhoCares is offline
who cares
 
Join Date: Jan 2002
Location: Here
Posts: 335
Rept. Given: 7
Rept. Rcvd 11 Times in 9 Posts
Thanks Given: 15
Thanks Rcvd at 56 Times in 26 Posts
WhoCares Reputation: 11
"b" is used as an incremental pointer/index to the buffer "a", so "b +=4;" can't be optimized out.

Later there are more parsing of the buffer data by calling the function e(a, b) many times.
__________________
AKA Solomon/blowfish.
Reply With Quote
  #10  
Old 03-09-2019, 02:27
chants chants is online now
Family
 
Join Date: Jul 2016
Posts: 447
Rept. Given: 1
Rept. Rcvd 30 Times in 18 Posts
Thanks Given: 357
Thanks Rcvd at 701 Times in 326 Posts
chants Reputation: 30
I just meant in those cases where caller never uses 'b' after the call then the assignment is optimizable (not the addition as you mention its an index):
Quote:
private uint e(byte[] a, ref int b)
{
return BitConverter.ToUInt32(a, b + 4);
}
Anyway that's too advanced an optimization anyway. But the bug found in multiple tools is a good one which should be reported and fixed.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Decompiling the mov compiler chants General Discussion 3 12-08-2016 21:16
Who are familiar with decompiling? DMichael General Discussion 3 08-09-2013 01:04
VB3 decompiling wasq General Discussion 23 05-23-2005 02:30


All times are GMT +8. The time now is 11:05.


��ICP��05004977��
Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX