对于我们的嵌入式设备,我们定义了RS232(COM端口)的通信协议。
现在我想做一些利用/漏洞测试,发送最大长度的所有可能的缓冲区。
所以我需要一些代码来创建给定长度的所有可能的字节模式的列表。
例如,对于给定的长度 2,我想要这个列表:
0x00
0x01
...
0xFF
0x0000
0x0001
...
0xFFFF
任何建议如何在 C# 中创建此列表?
感谢
基本代码总是相同的:a for 循环。要发送所有可能的值,您只需循环它们即可。
for (int i=0; i < numberOfBytes; ++i)
{
for (BigInteger j=0; j < BigInteger.Pow(2, i * 8); ++j)
{
SendData(j.ToByteArray());
}
}
我可能弄错了,但当前的问题似乎要求所有可能的字节序列长度不超过 N,这将需要很长时间才能发送,假设:
- 115200波特率
- 每字节 10 位
- 长度 N = 256^N 的可能字节序列数
- 我的数学是对的...
长度为 1 到 4 的可能序列数4311810304,总字节数为 17230332160,发送时间为 17 天。
所以最好的算法可能是(注意:需要直接发送缓冲区而不是存储它们):
public static List<byte[]> GetBuffers(int maxLength)
{
if (maxLength > 4) throw new InvalidOperationException("Fail");
var result = new List<byte[]>();
for (int i = 1; i <= maxLength; i++)
{
var max = 1 << (i * 8);
for (long j = 0; j < max; j++)
{
// Can remove the Reverse() if endianness/ordering doesn't matter
var buffer = BitConverter.GetBytes(j).Take(i).Reverse().ToArray());
result.Add(buffer);
}
}
return result;
}
如果您仍然想运行测试并且想要更长的序列,则可以根据@Adriano的答案将其修改为使用 BigInteger.ToByteArray。
解决方案:
private static void SequencesInner(byte[] bytes, int i, Action<byte[]> action)
{
if (i == bytes.Length)
{
action(bytes);
}
else
{
int j = i + 1;
for (int v = 0; v < 256; v++)
{
bytes[i] = Convert.ToByte(v);
SequencesInner(bytes, j, action);
}
}
}
private static void Sequences(int length, Action<byte[]> action)
{
for (int n = 1; n <= length; n++)
{
SequencesInner(new byte[n], 0, action);
}
}
完整代码:
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
namespace ConsoleApplication
{
class Program
{
private static void SequencesInner(byte[] bytes, int i, Action<byte[]> action)
{
if (i == bytes.Length)
{
action(bytes);
}
else
{
int j = i + 1;
for (int v = 0; v < 256; v++)
{
bytes[i] = Convert.ToByte(v);
SequencesInner(bytes, j, action);
}
}
}
private static void Sequences(int length, Action<byte[]> action)
{
for (int n = 1; n <= length; n++)
{
SequencesInner(new byte[n], 0, action);
}
}
static void Main()
{
var maxBufferSize = 2;
var outputFilePath = Path.GetTempFileName();
var sb = new StringBuilder();
using (var sw = new StreamWriter(outputFilePath))
{
Sequences(
maxBufferSize,
a => sw.WriteLine(sb.Clear().Append("0x").Append(String.Join("", Array.ConvertAll(a, x => x.ToString("X2", CultureInfo.InvariantCulture))))));
sw.Flush();
}
var process = Process.Start("notepad.exe", outputFilePath);
process.WaitForExit();
File.Delete(outputFilePath);
}
}
}
正如Weston指出的那样,这基本上是一个排列问题。
所以你可以使用他链接到的帖子 - https://stackoverflow.com/questions/852536/calculating-all-possible-sub-sequences-of-a-given-length-c 但他链接到的代码不会重复使用使用的字母,所以你不会得到你想要的排列的完整列表。 这可以通过修改该帖子中链接到的优秀代码(在此处找到 - http://www.interact-sw.co.uk/iangblog/2004/09/16/permuterate)来修复
using System;
using System.Collections.Generic;
public class PermuteUtils
{
// Returns an enumeration of enumerators, one for each permutation
// of the input.
public static IEnumerable<IEnumerable<T>> Permute<T>(IEnumerable<T> list, int count)
{
if (count == 0)
{
yield return new T[0];
}
else
{
int startingElementIndex = 0;
foreach (T startingElement in list)
{
IEnumerable<T> remainingItems = list;// - Removed to get all permutations AllExcept(list, startingElementIndex);
foreach (IEnumerable<T> permutationOfRemainder in Permute(remainingItems, count - 1))
{
yield return Concat<T>(
new T[] { startingElement },
permutationOfRemainder);
}
startingElementIndex += 1;
}
}
}
// Enumerates over contents of both lists.
public static IEnumerable<T> Concat<T>(IEnumerable<T> a, IEnumerable<T> b)
{
foreach (T item in a) { yield return item; }
foreach (T item in b) { yield return item; }
}
}
然后要做你想做的事情,我们只需要为所有十六进制数字获取 2、3 和 4 列表的排列
静态空 主(字符串[] 参数) { 字符[] 项 = 新字符[] { '0
', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; for (int length = 2; length <= 4; length++)
{
foreach (IEnumerable<char> permutation in PermuteUtils.Permute(items, length))
{
StringBuilder output = new StringBuilder("0x");
foreach (char c in permutation)
{
output.Append(c);
}
Console.WriteLine(output.ToString());
}
}
Console.WriteLine("Done");
Console.ReadLine();
}
所有排列都为您打印出来。 然后,您可以将其隐藏为所需的任何格式(或构建所需的格式,而不仅仅是字符串)。