C# غير آمنة قيمة صفيف نوع إلى صفيف بايت التحويلات
-
05-07-2019 - |
سؤال
أنا استخدم طريقة تمديد لتحويل تطفو المصفوفات في البايت المصفوفات:
public static unsafe byte[] ToByteArray(this float[] floatArray, int count)
{
int arrayLength = floatArray.Length > count ? count : floatArray.Length;
byte[] byteArray = new byte[4 * arrayLength];
fixed (float* floatPointer = floatArray)
{
fixed (byte* bytePointer = byteArray)
{
float* read = floatPointer;
float* write = (float*)bytePointer;
for (int i = 0; i < arrayLength; i++)
{
*write++ = *read++;
}
}
}
return byteArray;
}
أنا أفهم أن مجموعة هي مؤشر إلى الذاكرة المرتبطة معلومات عن نوع و عدد من العناصر.أيضا يبدو لي أن هناك أي وسيلة من التحويل من و إلى صفيف بايت بدون نسخ البيانات على النحو الوارد أعلاه.
هل فهمت هذا ؟ فإنه حتى يكون من المستحيل أن أكتب IL لإنشاء مجموعة من المؤشر ، نوع و طول بدون نسخ البيانات ؟
تحرير: شكرا على الإجابات ، تعلمت بعض الأساسيات و حصلت على محاولة الحيل الجديدة!
بعد البداية قبول ديفي لاندمان الجواب اكتشفت أنه في حين كانت رائعة StructLayout هاك يقوم بتحويل البايت المصفوفات في تعويم المصفوفات, أنها لا تعمل العكس.شرح:
[StructLayout(LayoutKind.Explicit)]
struct UnionArray
{
[FieldOffset(0)]
public Byte[] Bytes;
[FieldOffset(0)]
public float[] Floats;
}
static void Main(string[] args)
{
// From bytes to floats - works
byte[] bytes = { 0, 1, 2, 4, 8, 16, 32, 64 };
UnionArray arry = new UnionArray { Bytes = bytes };
for (int i = 0; i < arry.Bytes.Length / 4; i++)
Console.WriteLine(arry.Floats[i]);
// From floats to bytes - index out of range
float[] floats = { 0.1f, 0.2f, 0.3f };
arry = new UnionArray { Floats = floats };
for (int i = 0; i < arry.Floats.Length * 4; i++)
Console.WriteLine(arry.Bytes[i]);
}
يبدو أن CLR يرى كل من المصفوفات لها نفس الطول.إذا كانت البنية هي التي تم إنشاؤها من تعويم البيانات ، صفيف بايت طول قصيرة جدا.
المحلول
نعم, نوع المعلومات والبيانات في نفس كتلة الذاكرة ، بحيث من المستحيل إلا إذا قمت بالكتابة فوق نوع المعلومات في تعويم مجموعة لخداع النظام أنه صفيف بايت.التي من شأنها أن تكون قبيحة حقا هاك, و يمكن بسهولة تفجير...
هنا هو كيف يمكنك تحويل يطفو بدون تعليمات برمجية غير آمنة إذا كنت ترغب في:
public static byte[] ToByteArray(this float[] floatArray) {
int len = floatArray.Length * 4;
byte[] byteArray = new byte[len];
int pos = 0;
foreach (float f in floatArray) {
byte[] data = BitConverter.GetBytes(f);
Array.Copy(data, 0, byteArray, pos, 4);
pos += 4;
}
return byteArray;
}
نصائح أخرى
يمكنك استخدام قبيح هاك تغيير مؤقت الصفيف الخاص بك إلى byte[] باستخدام الذاكرة التلاعب.
هذا هو حقا سريعة وفعالة كما أنها لا تتطلب استنساخ البيانات بالتكرار على ذلك.
أنا اختبرت هذا الاختراق في كل من 32 و 64 بت نظام التشغيل ، لذلك يجب أن تكون محمولة.
المصدر + نموذج الاستخدام هو الحفاظ على https://gist.github.com/1050703 لكن لراحتك سوف لصقه هنا فضلا:
public static unsafe class FastArraySerializer
{
[StructLayout(LayoutKind.Explicit)]
private struct Union
{
[FieldOffset(0)] public byte[] bytes;
[FieldOffset(0)] public float[] floats;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct ArrayHeader
{
public UIntPtr type;
public UIntPtr length;
}
private static readonly UIntPtr BYTE_ARRAY_TYPE;
private static readonly UIntPtr FLOAT_ARRAY_TYPE;
static FastArraySerializer()
{
fixed (void* pBytes = new byte[1])
fixed (void* pFloats = new float[1])
{
BYTE_ARRAY_TYPE = getHeader(pBytes)->type;
FLOAT_ARRAY_TYPE = getHeader(pFloats)->type;
}
}
public static void AsByteArray(this float[] floats, Action<byte[]> action)
{
if (floats.handleNullOrEmptyArray(action))
return;
var union = new Union {floats = floats};
union.floats.toByteArray();
try
{
action(union.bytes);
}
finally
{
union.bytes.toFloatArray();
}
}
public static void AsFloatArray(this byte[] bytes, Action<float[]> action)
{
if (bytes.handleNullOrEmptyArray(action))
return;
var union = new Union {bytes = bytes};
union.bytes.toFloatArray();
try
{
action(union.floats);
}
finally
{
union.floats.toByteArray();
}
}
public static bool handleNullOrEmptyArray<TSrc,TDst>(this TSrc[] array, Action<TDst[]> action)
{
if (array == null)
{
action(null);
return true;
}
if (array.Length == 0)
{
action(new TDst[0]);
return true;
}
return false;
}
private static ArrayHeader* getHeader(void* pBytes)
{
return (ArrayHeader*)pBytes - 1;
}
private static void toFloatArray(this byte[] bytes)
{
fixed (void* pArray = bytes)
{
var pHeader = getHeader(pArray);
pHeader->type = FLOAT_ARRAY_TYPE;
pHeader->length = (UIntPtr)(bytes.Length / sizeof(float));
}
}
private static void toByteArray(this float[] floats)
{
fixed(void* pArray = floats)
{
var pHeader = getHeader(pArray);
pHeader->type = BYTE_ARRAY_TYPE;
pHeader->length = (UIntPtr)(floats.Length * sizeof(float));
}
}
}
واستخدام هي:
var floats = new float[] {0, 1, 0, 1};
floats.AsByteArray(bytes =>
{
foreach (var b in bytes)
{
Console.WriteLine(b);
}
});
هذا السؤال هو عكس ما هي أسرع طريقة لتحويل تعويم[] إلى byte[]?.
لقد أجبت مع الاتحاد النوع من الإختراق لتخطي كله نسخ من البيانات.هل يمكن بسهولة عكس هذا (الطول = الطول *sizeof(مزدوجة).
لقد كتبت شيئا من هذا القبيل على تحويل سريع بين المصفوفات.انها في الاساس قبيحة إثبات صحة مفهوم أكثر من وسيم الحل.;)
public static TDest[] ConvertArray<TSource, TDest>(TSource[] source)
where TSource : struct
where TDest : struct {
if (source == null)
throw new ArgumentNullException("source");
var sourceType = typeof(TSource);
var destType = typeof(TDest);
if (sourceType == typeof(char) || destType == typeof(char))
throw new NotSupportedException(
"Can not convert from/to a char array. Char is special " +
"in a somewhat unknown way (like enums can't be based on " +
"char either), and Marshal.SizeOf returns 1 even when the " +
"values held by a char can be above 255."
);
var sourceByteSize = Buffer.ByteLength(source);
var destTypeSize = Marshal.SizeOf(destType);
if (sourceByteSize % destTypeSize != 0)
throw new Exception(
"The source array is " + sourceByteSize + " bytes, which can " +
"not be transfered to chunks of " + destTypeSize + ", the size " +
"of type " + typeof(TDest).Name + ". Change destination type or " +
"pad the source array with additional values."
);
var destCount = sourceByteSize / destTypeSize;
var destArray = new TDest[destCount];
Buffer.BlockCopy(source, 0, destArray, 0, sourceByteSize);
return destArray;
}
}
public byte[] ToByteArray(object o)
{
int size = Marshal.SizeOf(o);
byte[] buffer = new byte[size];
IntPtr p = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(o, p, false);
Marshal.Copy(p, buffer, 0, size);
}
finally
{
Marshal.FreeHGlobal(p);
}
return buffer;
}
هذا قد تساعدك على تحويل كائن إلى صفيف بايت.
يجب عليك التحقق من جوابي على سؤال مماثل: ما هي أسرع طريقة لتحويل تعويم[] إلى byte[]?.
في ذلك ستجد رمز المحمولة (32/64 بت متوافق) لتمكنك من عرض تطفو مجموعة صفيف بايت أو العكس دون نسخ البيانات.إنها أسرع طريقة أن أعرف أن تفعل مثل هذا الشيء.
إذا كنت مهتمة فقط في المدونة ، هو الحفاظ على https://gist.github.com/1050703 .
حسنا إذا كنت لا تزال ترغب في أن الإختراق - تحقق من هذا تعديل التعليمات البرمجية يعمل مثل السحر و تكاليف ~0 الوقت, ولكن قد لا تعمل في المستقبل لأنه هو الإختراق يسمح للحصول على حق الوصول الكامل إلى كل مساحة عنوان العملية دون الثقة متطلبات غير آمنة علامات.
[StructLayout(LayoutKind.Explicit)]
struct ArrayConvert
{
public static byte[] GetBytes(float[] floats)
{
ArrayConvert ar = new ArrayConvert();
ar.floats = floats;
ar.length.val = floats.Length * 4;
return ar.bytes;
}
public static float[] GetFloats(byte[] bytes)
{
ArrayConvert ar = new ArrayConvert();
ar.bytes = bytes;
ar.length.val = bytes.Length / 4;
return ar.floats;
}
public static byte[] GetTop4BytesFrom(object obj)
{
ArrayConvert ar = new ArrayConvert();
ar.obj = obj;
return new byte[]
{
ar.top4bytes.b0,
ar.top4bytes.b1,
ar.top4bytes.b2,
ar.top4bytes.b3
};
}
public static byte[] GetBytesFrom(object obj, int size)
{
ArrayConvert ar = new ArrayConvert();
ar.obj = obj;
ar.length.val = size;
return ar.bytes;
}
class ArrayLength
{
public int val;
}
class Top4Bytes
{
public byte b0;
public byte b1;
public byte b2;
public byte b3;
}
[FieldOffset(0)]
private Byte[] bytes;
[FieldOffset(0)]
private object obj;
[FieldOffset(0)]
private float[] floats;
[FieldOffset(0)]
private ArrayLength length;
[FieldOffset(0)]
private Top4Bytes top4bytes;
}