18

Hei. I was reading Digi Traffic Accelerator's decompiled source (I think it is the best way to learn), until I got some non-understandable code! Please take a look:

  internal class ProxyFarm
  {
    private static Random rand = new Random();
    private static Regex UserPassAtHostPort = new Regex("\r\n                ^\r\n                (?<user>[^:]+?) : (?<pass>[^@]+?)\r\n                @\r\n                (?<host>[^:]+? (?: : \\d+)? )\r\n                $", RegexOptions.IgnorePatternWhitespace);
    private static Regex HostPortUserPass = new Regex("\r\n                ^\r\n                (?<host>[^:]+? : \\d+) : (?<user>[^:]+?) : (?<pass>.+?)\r\n                $", RegexOptions.IgnorePatternWhitespace);
    public const string NEW = "new";
    public const string ACTIVE = "active";
    public const string BLOCKED_BY_GOOGLE = "blocked by Google";
    public const string INACTIVE = "inactive";
    public const string CHECKING = "Checking...";

    static ProxyFarm()
    {
    }

    public static StorageDataSet.ProxiesRow GetRandomProxy(bool WillUseRecaptcha = true)
    {
      // some normal code
    }

    public static WebProxy MakeWebProxy(StorageDataSet.ProxiesRow row)
    {
      // some normal code
    }

    public static void CheckProxy(StorageDataSet.ProxiesRow proxy)
    {
      // ISSUE: object of a compiler-generated type is created
      // ISSUE: variable of a compiler-generated type
      ProxyFarm.\u003C\u003Ec__DisplayClass5 cDisplayClass5 = new ProxyFarm.\u003C\u003Ec__DisplayClass5();
      // ISSUE: reference to a compiler-generated field
      cDisplayClass5.proxy = proxy;
      // ISSUE: reference to a compiler-generated field
      if (cDisplayClass5.proxy == null)
        return;
      // ISSUE: reference to a compiler-generated field
      cDisplayClass5.logger = LogManager.GetLogger("Program");
      // ISSUE: reference to a compiler-generated field
      // ISSUE: reference to a compiler-generated field
      cDisplayClass5.state = new ProxyFarm.CallbackState()
      {
        Proxy = cDisplayClass5.proxy,
        Google = ProxyFarm.CheckStatus.NotChecked,
        Post = ProxyFarm.CheckStatus.NotChecked
      };
      // ISSUE: reference to a compiler-generated field
      cDisplayClass5.r = (HttpWebRequest) WebRequest.Create("http://www.digitrafficgenerator.com/post_test.php");
      // ISSUE: reference to a compiler-generated field
      cDisplayClass5.r.Method = "POST";
      try
      {
        // ISSUE: reference to a compiler-generated field
        // ISSUE: reference to a compiler-generated field
        cDisplayClass5.r.Proxy = (IWebProxy) ProxyFarm.MakeWebProxy(cDisplayClass5.proxy);
      }
      catch (Exception ex)
      {
        // ISSUE: reference to a compiler-generated field
        // ISSUE: reference to a compiler-generated field
        cDisplayClass5.logger.Warn((object) ("Invalid proxy entered: " + cDisplayClass5.proxy.Address), ex);
        // ISSUE: reference to a compiler-generated field
        ProxyFarm.ChangeStatus(cDisplayClass5.proxy, "inactive");
        return;
      }
      // ISSUE: reference to a compiler-generated field
      cDisplayClass5.r.ConnectionGroupName = Guid.NewGuid().ToString();
      // ISSUE: reference to a compiler-generated field
      cDisplayClass5.byteArray = Encoding.UTF8.GetBytes("q=test");
      // ISSUE: reference to a compiler-generated field
      // ISSUE: reference to a compiler-generated field
      cDisplayClass5.r.ContentLength = (long) cDisplayClass5.byteArray.Length;
      // ISSUE: reference to a compiler-generated field
      cDisplayClass5.r.ContentType = "application/x-www-form-urlencoded";
      // ISSUE: reference to a compiler-generated field
      cDisplayClass5.r.Referer = "http://www.digitrafficgenerator.com/post_test.php";
      // ISSUE: reference to a compiler-generated field
      cDisplayClass5.r.Timeout = 20000;
      // ISSUE: reference to a compiler-generated field
      // ISSUE: reference to a compiler-generated method
      IAsyncResult res = cDisplayClass5.r.BeginGetRequestStream(new AsyncCallback(cDisplayClass5.\u003CCheckProxy\u003Eb__1), (object) null);
      // ISSUE: reference to a compiler-generated field
      WebObject.AbortRequestAfterTimeout(res, cDisplayClass5.r);
      try
      {
        // ISSUE: reference to a compiler-generated field
        // ISSUE: reference to a compiler-generated method
        // ISSUE: reference to a compiler-generated field
        res = cDisplayClass5.r.BeginGetResponse(new AsyncCallback(cDisplayClass5.\u003CCheckProxy\u003Eb__2), (object) cDisplayClass5.r);
      }
      catch (Exception ex)
      {
        // ISSUE: reference to a compiler-generated field
        // ISSUE: reference to a compiler-generated field
        cDisplayClass5.logger.Info((object) ("Got an exception using " + cDisplayClass5.proxy.Address), ex);
      }
      // ISSUE: reference to a compiler-generated field
      WebObject.AbortRequestAfterTimeout(res, cDisplayClass5.r);
      HttpWebRequest request = (HttpWebRequest) WebRequest.Create("http://www.google.com/recaptcha/api/js/recaptcha.js");
      request.Method = "GET";
      // ISSUE: reference to a compiler-generated field
      request.Proxy = (IWebProxy) ProxyFarm.MakeWebProxy(cDisplayClass5.proxy);
      request.Timeout = 20000;
      request.ConnectionGroupName = Guid.NewGuid().ToString();
      // ISSUE: reference to a compiler-generated method
      WebObject.AbortRequestAfterTimeout(request.BeginGetResponse(new AsyncCallback(cDisplayClass5.\u003CCheckProxy\u003Eb__3), (object) request), request);
    }

    protected static void ProxyChecked(IAsyncResult result, HttpWebRequest req, ProxyFarm.CallbackState state)
    {
      ILog logger = LogManager.GetLogger("Program");
      ProxyFarm.CheckStatus checkStatus = ProxyFarm.CheckStatus.NotOk;
      try
      {
        HttpWebResponse httpWebResponse = (HttpWebResponse) req.EndGetResponse(result);
        if (req.RequestUri == httpWebResponse.ResponseUri)
        {
          if (httpWebResponse.StatusCode == HttpStatusCode.OK)
            checkStatus = ProxyFarm.CheckStatus.Ok;
        }
      }
      catch (Exception ex)
      {
      }
      lock (state)
      {
        if (req.RequestUri.Authority.Contains("google.com"))
          state.Google = checkStatus;
        else
          state.Post = checkStatus;
        if (state.Post == ProxyFarm.CheckStatus.NotOk)
        {
          ProxyFarm.ChangeStatus(state.Proxy, "inactive");
          logger.Info((object) ("Marking " + state.Proxy.Address + " as inactive as it cannot POST"));
        }
        else if (state.Google == ProxyFarm.CheckStatus.NotOk)
        {
          ProxyFarm.ChangeStatus(state.Proxy, "inactive");
          logger.Info((object) ("Marking " + state.Proxy.Address + " as inactive as it is blocked by google"));
        }
        else
        {
          if (state.Google != ProxyFarm.CheckStatus.Ok || state.Post != ProxyFarm.CheckStatus.Ok)
            return;
          ProxyFarm.ChangeStatus(state.Proxy, "active");
        }
      }
    }

    public static void ReportBrokenProxy(StorageDataSet.ProxiesRow proxy, bool recaptcha_fail = false)
    {
      // some normal code
    }

    private static void ChangeStatus(StorageDataSet.ProxiesRow Proxy, string status)
    {
      // some normal code
    }

    public enum CheckStatus
    {
      NotChecked,
      Ok,
      NotOk,
    }

    protected class CallbackState
    {
      public StorageDataSet.ProxiesRow Proxy { get; set; }

      public ProxyFarm.CheckStatus Post { get; set; }

      public ProxyFarm.CheckStatus Google { get; set; }
    }
  }

As you can see, it seems in CheckProxy method, the compiler generated a new type! Do you have any idea what is really happening in this method? How can I understand the code?

amiry jd
  • 27,021
  • 30
  • 116
  • 215
  • This is a decompiler deficiency, report it. – usr Feb 07 '16 at 12:22
  • This is from five years ago, and I think dotPeek is handling some of these characters better now. But it still does weird things. If you have a dollar sign ($) in an identifier (not valid in C# but valid in IL), then in some contexts dotPeek shows $ correctly and also works if you search for the identifier. In other contexts it shows a $ character, but behind the scenes it has converted it to "\u0024". This becomes apparent if you do a copy-and-paste to a text editor, and it also means that when trying to find that identifier that these lines are not found. – RenniePet Jun 14 '18 at 12:44

2 Answers2

20

\u003C and \u003E are the unicode representations of < and > respectively.

Those characters are valid in IL.. so the compiler will generate variables with names like that to avoid collisions.

Your decompiler just didn't know how to convert it to <> and didn't remove the temporary variables.

Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138
  • Thanks to answer. I understand. So if you want to rewrite the `CheckProxy` method, how will you do? I mean, why the compiler generates the `<>__DisplayClass5` class? Which conditions make compiler to do this stuffs? – amiry jd Apr 10 '13 at 01:47
  • 1
    The compiler will do this for things like Closures, Anonymous Types, or when you're using an object through a `try..finally` clause. The exact semantics I am unfamiliar with.. however it isn't really an issue. – Simon Whitehead Apr 10 '13 at 02:26
10

Open it in dnSpy and look around for a method that matches(ish). They will be in a different order but dnSpy does a decent job of decompiling lambdas.

CAD bloke
  • 8,578
  • 7
  • 65
  • 114
  • Thanks for this, just had much better results from this in comparison to dotpeek – Liam May 13 '16 at 14:33
  • 6
    I followed this answer and went and got dnSpy, but after much mucking around trying to get it to build then debug (don't try publishing it!) the end results weren't any clearer than dotPeek – Matt Kemp Sep 08 '17 at 05:19
  • Thank you for this, the result from dnSpy is much more accurate – Jean-Daniel Gasser Mar 20 '20 at 11:26