I'm trying to create a MD5 malware scanner using C#. Using normal dictionary comparison has a fatal flaw, there exists duplicate files with the same hash across directories so, the same key (md5) would represent a lot of file directories to relate with. I tried switching to KeyValuePair<> but due to my inexperience, I still can't figure out how to insert lambda coordinate output into KeyValuePair<> (represented by Idon'tknowwhatshouldbehere in the code below).
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Diagnostics;
using System.Text;
using System.Web;
using static System.Net.WebRequestMethods;
namespace RiskRemover
{
class Program
{
private static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
var currDir = Directory.GetCurrentDirectory();
Console.WriteLine("Stage 1: Update");
HttpWebRequest updRq = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/drive/v3/files/15WR2yTVJzgwg2pn64IhxFUbfy2BmmsdL?alt=media&key=APIKey");
updRq.Referer = "referrer";
HttpWebResponse updRqF = (HttpWebResponse)updRq.GetResponse();
using (Stream output = System.IO.File.OpenWrite("virushashesL.txt"))
using (Stream input = updRqF.GetResponseStream())
{
input.CopyTo(output);
}
bool dbExist = System.IO.File.Exists($"{currDir}\\virushashesL.txt");
if (!dbExist)
{
Console.WriteLine("Database Doesn't exist, Terminating...");
return;
}
var lineCount = System.IO.File.ReadLines($"{currDir}\\virushashesL.txt").Count();
Console.WriteLine(" ");
Console.WriteLine($"Database Hash Count: {lineCount}");
Console.WriteLine(" ");
Console.Write("Press any key to continue...");
Console.Clear();
Console.Write("Scan Path:");
string pathScan = #Console.ReadLine();
Console.Clear();
Console.WriteLine("Stage 2: MD5 Hashing");
var data = GetHasList(#pathScan, false).Select(x => $"\"{x.fileName}\" {x.hash}");
System.IO.File.WriteAllLines("output.txt", data);
Console.Clear();
Console.WriteLine("Stage 3: Comparing MD5 hashes to DB");
KeyValuePair<string, string> dic = new KeyValuePair<string, string>();
dic = System.IO.File.ReadAllLines("output.txt")
.Select(l => l.Split(new[] { '<' }))
.Idon'tknowwhatshouldbehere(s => s[1].Trim().Substring(0, 10), s => s[0].Trim());
List<string> lines = System.IO.File.ReadAllLines("virushashesL.txt").ToList();
foreach (var line in lines)
{
bool malicious = dic.ContainsKey(line);
if (malicious)
{
string malPath = dic[line];
System.IO.File.Delete(malPath);
}
}
Console.Clear();
sw.Stop();
Console.Write($"Done in {sw.Elapsed}...");
Console.ReadKey();
return;
}
public static IEnumerable<(string fileName, string hash)> GetHasList(string path, bool isRelative)
{
foreach (var file in Directory.GetFiles(path, "*.*", SearchOption.AllDirectories))
{
string hash;
using (var md5 = MD5.Create())
using (var stream = System.IO.File.OpenRead(file))
hash = BitConverter.ToString(md5.ComputeHash(stream)).ToLower();
hash = hash.Replace("-", "");
if (isRelative)
yield return (file.Remove(0, path.TrimEnd('/').Length + 1), hash);
else
yield return ($"{file}<", hash);
}
}
}
}
Example output.txt
"D:\EvaxHybrid\Downloads\CS8\insdir\CSMediaLibParser.dll<" a384ff0a72a89028fc5edc894309ce81
"D:\EvaxHybrid\Downloads\CS8\insdir\CSMediaLibTools.dll<" 62cd2374d3a2bbeb888a078dc20e6b18
...
Example virushashesL.txt
2d3f18345c
2d427ec2c7
...
I think you want to delete all paths with malware
ILookup<string, string> lookup = System.IO.File.ReadAllLines("output.txt")
.Select(l => l.Split(new[] { '<' }))
.Select(s => (key: s[1].Trim().Substring(0, 10), value: s[0].Trim())) // create a value tuple (string key, string value)
.ToLookup(s => s.key, s => s.value); // make a lookup from the tuples
List<string> lines = System.IO.File.ReadAllLines("virushashesL.txt").ToList();
foreach (var line in lines)
{
var malPaths = lookup[line];
// if the key is not found an empty sequence is returned
// so no further checks are neccessary
foreach (var malPath in malPaths)
{
// delete all malicious paths
System.IO.File.Delete(malPath);
}
}
D://output.txt
D:\EvaxHybrid\Downloads\CS8\insdir\CSMediaLibParser.dll< a384ff0a72a89028fc5edc894309ce81
D:\EvaxHybrid\Downloads\CS8\insdir\CSMediaLibTools.dll< 62cd2374d3a2bbeb888a078dc20e6b18
D://virushashesL.txt
a384ff0a72a89028fc5edc894309ce81
62cd2374d3a2bbeb888a078dc20e6b18
private void fileintodis()
{
List<KeyValuePair<string, string>> dic = new List<KeyValuePair<string, string>>();
dic = System.IO.File.ReadAllLines("D://output.txt").ToList()
.Select(l => new KeyValuePair<string, string>(l.Split('<')[1].Trim(), l.Split('<')[0].Trim())).ToList();
List<string> lines = System.IO.File.ReadAllLines("D://virushashesL.txt").ToList();
foreach (var line in lines)
{
bool malicious = dic.Where(s => s.Key.Trim() == line).Count() > 0 ? true : false;
if (malicious)
{
string malPath = dic.Where(s => s.Key == line).Select(e => e.Value).FirstOrDefault().ToString();
System.IO.File.Delete(malPath);
}
}
}
Related
I have a file in which i have to read text between startscriptexpression$ and Finish scriptExpression$, and also read between startupdatedescription$ and startupdatedescription$[
The problem is that i want to re write the code in a cleaner format.
My Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Vesrion
{
class Program
{
static void Main(string[] args)
{
string path = #"C:\Users\Development\Desktop\Read\Test.txt";
using (var reader = new StreamReader(path))
{
var textInBetween = new List<string>();
var ListOFDescription = new List<string>();
string NewString = "";
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
//Reads First line,
switch (line)
{
case "StartScriptExpression$":
continue;
case "FinishScriptExpression$":
if (line.Contains("FinishScriptExpression$"))
{
line = "";
}
string Something = string.Join("", textInBetween);
textInBetween = line.Split(',').ToList();
string[] lines = Something.Split(
new string[] { Environment.NewLine },
StringSplitOptions.None);
foreach (var S in lines)
{
ListOFDescription.Add(S);
Console.WriteLine(S);
}
NewString += ListOFDescription;
break;
case "StartUpdateDescription$":
//Console.WriteLine(Environment.NewLine);
continue;
case "FinishUpdateDescription$":
// Console.WriteLine(Environment.NewLine);
continue;
default:
textInBetween.Add(line);
//Console.WriteLine(line);
break;
}
}
}
}
}
}
Text inside start and finish expression must be in a list of string array.
text inside startupdatedescription and finishupdatedescription must be in a string.
.
One way to do it is using regular expression https://dotnetfiddle.net/pxBAMv
I'm getting this error:
would not find a GetExtension method
Code:
public static void Main()
{
string[] arr = {"abc.txt", "asd.TXT","bvc.pdf","fgd.txt","hss.pdf","djhd.xml"};
var arrp = arr.Select(file=>Path.GetExtension(file).TrimStart('.').ToLower()).GroupBy(x=>x,(ext,extcnt)=>new
{
Extension = ext,
count=extcnt.Count()
});
foreach(var v in arrp)
{
Console.WriteLine("{0} files(s) with {1} Extension", v.Count,v.Extension );
Console.ReadLine();
}
}
How can I fix it?
First check, do you have added the using statment? using System.IO;
Second change your code line:
Console.WriteLine("{0} files(s) with {1} Extension", v.Count, v.Extension);
to:
Console.WriteLine("{0} files(s) with {1} Extension", v.count, v.Extension);
i had created a new console application. This example works in my enviroment:
using System;
using System.IO;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string[] arr = { "abc.txt", "asd.TXT", "bvc.pdf", "fgd.txt", "hss.pdf", "djhd.xml" };
var arrp = arr.Select(file => Path.GetExtension(file).TrimStart('.').ToLower()).GroupBy(x => x, (ext, extcnt) => new
{
Extension = ext,
count = extcnt.Count()
});
foreach (var v in arrp)
{
Console.WriteLine("{0} files(s) with {1} Extension", v.count, v.Extension);
Console.ReadLine();
}
}
}
}
i get this result:
Important: this is a console application! not a asp.net application! (you have added the asp.net tag.. )
I have some sql commands that are separated by an additional newline character:
ALTER TABLE XXX
ALTER COLUMN xxx real
ALTER TABLE YYY
ALTER COLUMN yyy real
ALTER TABLE ZZZ
ALTER COLUMN zzz real
I've tried reading the file by using an array of character separators such as the following,
new char[] { '\n', '\r'}
inside this method:
private static List<string> ReadFile(string FileName, char[] seps)
{
if (!File.Exists(FileName))
{
Console.WriteLine("File not found");
return null;
}
using (StreamReader sr = new StreamReader(FileName, Encoding.Default))
{
string content = sr.ReadToEnd();
return content.Split(seps, StringSplitOptions.RemoveEmptyEntries).ToList();
}
}
However, this doesn't seem to be working. I would like to have each command represented by a separate string. How can I do this?
Why not use File.ReadAllLines()?
private static List<string> ReadFile(string FileName)
{
if (!File.Exists(FileName))
{
Console.WriteLine("File not found");
return null;
}
var lines = File.ReadAllLines(FileName);
return lines.ToList();
}
This will automatically read and split your file by newlines.
If you want to filter out empty lines, do this:
var nonEmpty = ReadFile(path).Where(x => !string.IsNullOrEmpty(x)).ToList();
Side note, I would change your if statement to throw an exception if the file cannot be found.
if (!File.Exists(FileName))
{
throw new FileNotFoundException("Can't find file");
}
You can filter the examples. When I read them in, the empty lines had a length 1 and its char value said 131 for some reason. So I just filtered by length > 1
void Main()
{
var results = ReadFile(#"C:\temp\sql.txt", new char[]{'\n'});
Console.WriteLine(results.Count);
foreach (var result in results)
{
Console.WriteLine(result);
}
}
private static List<string> ReadFile(string FileName, char[] seps)
{
if (!File.Exists(FileName))
{
Console.WriteLine("File not found");
return null;
}
using (StreamReader sr = new StreamReader(FileName, Encoding.Default))
{
string content = sr.ReadToEnd();
return content.Split(seps, StringSplitOptions.RemoveEmptyEntries).Where (c => c.Length > 1).ToList();
}
}
Try This:
private static List<string> ReadFile(string FileName)
{
List<string> commands = new List<string>();
StringBuilder command = new StringBuilder();
if (!File.Exists(FileName))
{
Console.WriteLine("File not found");
return null;
}
foreach (var line in File.ReadLines(FileName))
{
if (!String.IsNullOrEmpty(line))
{
command.Append(line + "\n");
}
else
{
commands.Add(command.ToString());
command.Clear();
}
}
commands.Add(command.ToString());
return commands;
}
If you are sure you'll always have \r\n line endings, you can use:
var commands = content.Split(new []{"\r\n\r\n"}, StringSplitOptions.RemoveEmptyEntries);
Otherwise, try using regex:
var commands = Regex.Split(content, #"\r?\n\r?\n")
Thank you everyone for your answers. I ended up going with this helper method:
private static List<string> GetCommands(string location)
{
List<string> ret = new List<string>();
List<string> tmp = ReadFile(location, new string[] { "\r\n\r\n"});
for (int i = 0; i < tmp.Count; i++)
{
string rem = tmp[i].Replace("\r", "");
ret.Add(rem);
}
return ret;
}
As an aside, the equivalent is so much easier in Python. For example, what I'm trying to do can be expressed in these three lines:
with open('commands.txt', 'r') as f:
content = f.read()
commands = [ command for command in content.split('\n\n') ]
What I'm trying to accomplish is have a ConsoleKey assigned to a variable then using ConsoleKeyInfo to modify the variable.
I'm getting errors saying Cannot convert source type 'System.ConsoleKey' to target type 'System.ConsoleKeyInfo'.
The reasoning behind this is I wish to have the user be able to reprogram the keys used inside the application.
I have this so far;
public static ConsoleKeyInfo keyboardkeynorth;
keyboardkeynorth = Console.ReadKey();
This works, but it doesn't allow me to start the program with keyboardkeynorth already set to ConsoleKey.W.
Elsewhere in the program I would call keyboardkeynorth to be used as a ConsoleKey
This may be simple but it seems to be eluding me.
Realizing this is a short 3+ years after you asked...
public static ConsoleKeyInfo keyboardkeynorth =
new ConsoleKeyInfo('W', ConsoleKey.W, false, false, false);
And don't you want "north" to be 'N' initially? ;^)
It's a strange, verbose constructor, but does what you appear to be asking.
Here is a complete, and simple, program to show you how you might do this. I say simple because it doesn't take into consideration CTRL, ALT, or SHIFT -- and based on how I gather the custom key info you wouldn't even be able to set those because I'm using ReadKey. But you'll get the idea.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
namespace ConsoleApplication23
{
class Program
{
private static ConsoleKeyInfo keyAction1, keyAction2, keyAction3;
static void Main(string[] args)
{
InitializeKeyActions();
Console.Write("Do you want a new key action for #1? ");
var result = Console.ReadKey();
if (result.Key != ConsoleKey.Enter) { UpdateKeyInfo("keyAction1", result); }
}
private static void UpdateKeyInfo(string keyName, ConsoleKeyInfo result)
{
var propertyInfo = typeof(Program).GetField(keyName, BindingFlags.NonPublic | BindingFlags.Static);
if (propertyInfo == null) { return; }
var key = result.KeyChar;
propertyInfo.SetValue(null, new ConsoleKeyInfo(key, (ConsoleKey)key, false, false, false));
StringBuilder keyActions = new StringBuilder();
foreach (var line in File.ReadAllLines("keyactions.ini"))
{
var kvp = line.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
if (kvp[0] != keyName)
{
keyActions.AppendLine(line);
continue;
}
keyActions.AppendLine(string.Format("{0}: {1}", kvp[0], result.KeyChar));
}
File.WriteAllText("keyactions.ini", keyActions.ToString());
}
private static void InitializeKeyActions()
{
if (!File.Exists("keyactions.ini"))
{
StringBuilder keyActions = new StringBuilder();
keyActions.AppendLine("keyAction1: A");
keyActions.AppendLine("keyAction2: B");
keyActions.AppendLine("keyAction3: C");
File.WriteAllText("keyactions.ini", keyActions.ToString());
}
foreach (var line in File.ReadAllLines("keyactions.ini"))
{
var kvp = line.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
var propertyInfo = typeof(Program).GetField(kvp[0], BindingFlags.NonPublic | BindingFlags.Static);
if (propertyInfo == null) { continue; }
var key = kvp[1].Trim()[0];
propertyInfo.SetValue(null, new ConsoleKeyInfo(key, (ConsoleKey)key, false, false, false));
}
}
}
}
My file named as test.txt contains
This document is divided into about 5 logical sections starting with a feature and structure overview, followed by an overview of built in column and cell types. Next is an overview of working with data, followed by an overview of specific major features. Lastly, a “best practice” section concludes the main part of this document.
Now i want to delete 2nd line of the file.
How to do it using c#?
Thanks in advance.
Naveenkumar
List<string> lines = File.ReadAllLines(#"filename.txt").ToList();
if(lines.Count>lineNum){
lines.RemoveAt(lineNum);
}
File.WriteAllLines(#"filename.txt",lines.ToArray());
You can acheive this by splitting the text by \n and then using LINQ to select the lines you want to keep, and re-joining them.
var lineNum=5;
var lines=File
.ReadAllText(#"src.txt")
.Split('\n');
var outTxt=String
.Join(
"\n",
lines
.Take(lineNum)
.Concat(lines.Skip(lineNum+1))
.ToArray()
);
Here's a pretty efficient way to do it.
FileInfo x = new FileInfo(#"path\to\original");
string xpath = x.FullName;
FileInfo y = new FileInfo(#"path\to\temporary\new\file");
using (var reader = x.OpenText())
using (var writer = y.AppendText())
{
// write 1st line
writer.WriteLine(reader.ReadLine());
reader.ReadLine(); // skip 2nd line
// write all remaining lines
while (!reader.EndOfStream)
{
writer.WriteLine(reader.ReadLine());
}
}
x.Delete();
y.MoveTo(xpath);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace rem2ndline
{
class Program
{
static void Main(string[] args)
{
string inPath = #"c:\rem2ndline.txt";
string outPath = #"c:\rem2ndlineresult.txt";
StringBuilder builder = new StringBuilder();
using (FileStream fso = new FileStream(inPath, FileMode.Open))
{
using (StreamReader rdr = new StreamReader(fso))
{
int lineCount = 0;
bool canRead = true;
while (canRead)
{
var line = rdr.ReadLine();
lineCount++;
if (line == null)
{
canRead = false;
}
else
{
if (lineCount != 2)
{
builder.AppendLine(line);
}
}
}
}
}
using(FileStream fso2 = new FileStream(outPath, FileMode.OpenOrCreate))
{
using (StreamWriter strw = new StreamWriter(fso2))
{
strw.Write(builder.ToString());
}
}
}
}
}
Here's what I'd do. The advantage is that you don't have to have the file in memory all at once, so memory requirements should be similar for files of varying sizes (as long as the lines contained in each of the files are of similar length). The drawback is that you can't pipe back to the same file - you have to mess around with a Delete and a Move afterwards.
The extension methods may be overkill for your simple example, but those are two extension methods I come to rely on again and again, as well as the ReadFile method, so I'd typically only have to write the code in Main().
class Program
{
static void Main()
{
var file = #"C:\myFile.txt";
var tempFile = Path.ChangeExtension(file, "tmp");
using (var writer = new StreamWriter(tempFile))
{
ReadFile(file)
.FilterI((i, line) => i != 1)
.ForEach(l => writer.WriteLine(l));
}
File.Delete(file);
File.Move(tempFile, file);
}
static IEnumerable<String> ReadFile(String file)
{
using (var reader = new StreamReader(file))
{
while (!reader.EndOfStream)
{
yield return reader.ReadLine();
}
}
}
}
static class IEnumerableExtensions
{
public static IEnumerable<T> FilterI<T>(
this IEnumerable<T> seq,
Func<Int32, T, Boolean> filter)
{
var index = 0;
foreach (var item in seq)
{
if (filter(index, item))
{
yield return item;
}
index++;
}
}
public static void ForEach<T>(
this IEnumerable<T> seq,
Action<T> action)
{
foreach (var item in seq)
{
action(item);
}
}
}