C# - >罗斯林 - >找到所有字符串,如unix“strings”命令,并能够操作它们

时间:2018-03-15 16:47:48

标签: c# string compilation roslyn

正如标题所说,我想找到Roslyn的所有字符串,并能够操纵它们。我已经创建了一个程序,可以获取所有类和本地声明,但我希望有一些方法可以提取字符串。

在最佳世界中,我希望能够为以下字符串获取键值对,并避免使用int i = 0;var i2 = 0;

var test = "test";

string test1 = "testing";

String test2 = "testing 2";

我现在有什么:

{
    class Program
    {
        static void Main(string[] args)
        {
            var workspace = MSBuildWorkspace.Create();

            SyntaxTree tree = CSharpSyntaxTree.ParseText(
                @"using System;
using System.Collections;
using System.Linq;
using System.Text;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            var test = ""test"";

            string test1 = ""testing"";

            String test2 = ""testing 2"";

            int i = 0;

            var i2 = 0;
        }
    }
}");
            var root = (CompilationUnitSyntax)tree.GetRoot();

            var classVisitor = new ClassVirtualizationVisitor();
            classVisitor.Visit(root);

            var classes = classVisitor.Classes;

            var localDeclaration = new LocalDeclarationVirtualizationVisitor();
            localDeclaration.Visit(root);

            var localDeclarations = localDeclaration.LocalDeclarations;

        }
    }

class LocalDeclarationVirtualizationVisitor : CSharpSyntaxRewriter
{
    public LocalDeclarationVirtualizationVisitor()
    {
        LocalDeclarations = new List<LocalDeclarationStatementSyntax>();
    }

    public List<LocalDeclarationStatementSyntax> LocalDeclarations { get; set; }

    public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node)
    {
        node = (LocalDeclarationStatementSyntax)base.VisitLocalDeclarationStatement(node);
        LocalDeclarations.Add(node); 
        return node;
    }
}


    class ClassVirtualizationVisitor : CSharpSyntaxRewriter
    {
        public ClassVirtualizationVisitor()
        {
            Classes = new List<ClassDeclarationSyntax>();
        }

        public List<ClassDeclarationSyntax> Classes { get; set; }

        public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
        {
            node = (ClassDeclarationSyntax)base.VisitClassDeclaration(node);
            Classes.Add(node); // save your visited classes
            return node;
        }
    }
}

示例程序:

using System;
using System.Collections;
using System.Linq;
using System.Text;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            var test = "test";

            string test1 = "testing";

            String test2 = "testing 2";

            int i = 0;

            var i2 = 0;
        }
    }
}

使用Strings v2.53中的SysInternals我会在.exe下面得到以下字符串,我想从Roslyn那里获得相同的信息。

https://docs.microsoft.com/sv-se/sysinternals/downloads/strings

!This program cannot be run in DOS mode.
.text
`.rsrc
@.reloc
BSJB
v4.0.30319
#Strings
#US
#GUID
#Blob
T.#]
<Module>
mscorlib
HelloWorld
DebuggableAttribute
TargetFrameworkAttribute
CompilationRelaxationsAttribute
RuntimeCompatibilityAttribute
ObfuscationConsoleApp.exe
System.Runtime.Versioning
Program
System
Main
ObfuscationConsoleApp
.ctor
System.Diagnostics
System.Runtime.CompilerServices
DebuggingModes
args
Object
test
testing
testing 2
z\V
WrapNonExceptionThrows
.NETFramework,Version=v4.6.1
FrameworkDisplayName
.NET Framework 4.6.1
RSDS
g1M
|EF\R}
C:\Users\Oscar\source\repos\ObfuscationConsoleApp\ObfuscationConsoleApp\obj\Debug\ObfuscationConsoleApp.pdb
_CorExeMain
mscoree.dll
VS_VERSION_INFO
VarFileInfo
Translation
StringFileInfo
000004b0
FileDescription
FileVersion
0.0.0.0
InternalName
ObfuscationConsoleApp.exe
LegalCopyright
OriginalFilename
ObfuscationConsoleApp.exe
ProductVersion
0.0.0.0
Assembly Version
0.0.0.0
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
        <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

2 个答案:

答案 0 :(得分:3)

非常感谢@MarcGravell和http://roslynquoter.azurewebsites.net/上的服务(请务必选中“保留冗余API调用”复选框)或https://github.com/KirillOsenkov/RoslynQuoter

打印字符串键值对的最终代码:

var localDeclaration = new LocalDeclarationVirtualizationVisitor();
localDeclaration.Visit(root);

var localDeclarations = localDeclaration.LocalDeclarations;

foreach (var localDeclarationStatementSyntax in localDeclarations)
{
    foreach (VariableDeclaratorSyntax variable in localDeclarationStatementSyntax.Declaration.Variables)
    {
        var stringKind = variable.Initializer.Value.Kind();

        if (stringKind == SyntaxKind.StringLiteralExpression)
        {                       
            Console.WriteLine($"Key: {variable.Identifier.Value} Value:{variable.Initializer.Value}");
        }
    }
}

答案 1 :(得分:0)

基于公认的答案,这对我有帮助:

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace CodeScanner
{
  class StringsCollector : CSharpSyntaxWalker
  {
    public List<String> _strings = new List<string>();

    public override void VisitLiteralExpression(LiteralExpressionSyntax node)
    {
      if (node.IsKind(SyntaxKind.StringLiteralExpression))
      {
        // StringLiteralToken stringLiteralToken = node.Token;
        // Console.WriteLine(node.Token.Value);
        _strings.Add((string) node.Token.Value);
      }

    }
  }
  class Program
  {
    const string programText =
      @"using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace TopLevel
{
    using Microsoft;
    using System.ComponentModel;

    namespace Child1
    {
        using Microsoft.Win32;
        using System.Runtime.InteropServices;

        class Foo { }
    }

    namespace Child2
    {
        using System.CodeDom;
        using Microsoft.CSharp;

        class Bar {
          public string test = ""str1\n\t"";

          public void test()
          {
            Console.WriteLine(""str2"");
          }

        }
    }
}";

    private const string _rootDir = @"<replace here with your root dir>";

    static List<string> GetAllCSharpCode(string folder)
    {
      List<string> result = new List<string>();
      result.AddRange(Directory.GetFiles(folder, "*.cs"));
      foreach (var directory in Directory.GetDirectories(folder).Where(d => !SkipDirectory(d)))
      {

        result.AddRange(GetAllCSharpCode(directory));
      }

      return result;
    }

    private static string[] skippedDirs = new string[] {"obj", "packages"};
    static bool SkipDirectory(string directory)
    {
      var lcDir = directory.ToLower();
      return skippedDirs.Any(sd => directory.EndsWith("\\" + sd));
    }
    static void Main(string[] args)
    {
      //PrintStrings(GetStrings(programText));

      //Console.WriteLine("Hello World!");
      var allCSharpFiles = GetAllCSharpCode(_rootDir);

      PrintStrings(allCSharpFiles);

      allCSharpFiles.ForEach(f =>
      {
        Console.WriteLine(f);
        PrintStrings(GetStrings(File.ReadAllText(f)));
      });
    }

    static void PrintStrings(List<string> list)
    {
      list.ForEach(Console.WriteLine);
    }
    private static List<string> GetStrings(string sourceCode)
    {
      SyntaxTree tree = CSharpSyntaxTree.ParseText(sourceCode);
      CompilationUnitSyntax root = tree.GetCompilationUnitRoot();

      var collector = new StringsCollector();
      collector.Visit(root);
      return collector._strings;
    }
  }
}

当然可以对代码进行调整,以满足其他要求。