PDA

View Full Version : سوال: خواندن محتوای متنی فایل های اجرایی (exe) !



مهران رسا
دوشنبه 15 مهر 1387, 23:01 عصر
سلام .

برای باز کردن فایلی در حالت باینری از کلاس BinaryReader به صورت زیر استفاده کردم :





BinaryReader Br = new BinaryReader(File.Open("C:\\file.exe",FileMode.Open ));



هدفم خواندن محتوای متنی فایل های اجرایی هست . برای مثال قستمی از محتوای متنی یک فایل exe به صورت زیر خواهد بود :





wE;\$s
‰\$‹‹‹Eًè<ِےے‹س‹^[أ‹ہƒà‹$é©ےےےأS‹طèŒ

از متد ReadByte استفاده کردم ولی به نتیجه نرسیدم. ابتدا تمامی Byte های فایل رو در یک آرایه قرار داده و پس از اون با استفاده از Encoding.ASCII.GetString ، بایت ها رو به رشته تبدیل کردم ولی نتیجه مورد نظر رو دریافت نکردم .
قصد دارم فایل رو به صورت رشته باز کنم و یک سری تغییرات متنی با استفاده از تابع Replace در اون ایجاد کنم و مجدداً فایل رو به صورت باینری بنویسم . (همچنین در دفعات بعدی این تغییرات به نحوی به حالت اولیه برگشت داده بشند که فایل اجرایی ایجاد شده توسط BinaryWriter سالم و قابل اجرا باشه).
از متد ReadString هم استفاده کردم ولی اگر درست متوجه شده باشم خطایی در مورد عدم توانایی در خواندن بعضی از کارکتر ها اعلام میشد که این مورد فقط در مورد فایل های exe صادق بود .
در واقع علاوه بر دو کاراکتری که در اول تمامی فایل های اجرایی وجود داره (MZ) هیچ قسمت دیگری از فایل خوانده نمیشد .

این کارعملی هست چون قبلا در VB6 بدون هیچ مشکلی انجام شده :





Strx$ = Space(FileLen("C:\File.exe"))


Open "C:\File.exe" For Binary As #1


Get #1, , Strx$


Close


FileText = Strx$



آیا راه حلی دارید ؟
ممنون !

SMRAH1
سه شنبه 16 مهر 1387, 04:21 صبح
سلام
چرا اصرار داری که به شکل متنی بخونی.در واقع به شکل باینری هم می تونی جستجو کنی،فقط باید تابع جستجو رو خودت بنویسی.
برای نمونه در جستجوی یک عبارت 5 بایتی،اول 5 یابت اول رو می خوانی،اگر برابر بود که جابجایی رو انجام می دی و 5 بابت بعدی رو می خوانی،اگر هم برابر نبود،5بایت قبلی رو به عقب شیفت می دی،(بایت اول حذف میشه و 4 بایت میمونه )، حالا بایت بعدی رو می خونی و جستجو رو روی 5 بایت جدید انجام میدی.

موفق باشی

مهران رسا
چهارشنبه 17 مهر 1387, 00:45 صبح
سلام
چرا اصرار داری که به شکل متنی بخونی.در واقع به شکل باینری هم می تونی جستجو کنی،فقط باید تابع جستجو رو خودت بنویسی.
برای نمونه در جستجوی یک عبارت 5 بایتی،اول 5 یابت اول رو می خوانی،اگر برابر بود که جابجایی رو انجام می دی و 5 بابت بعدی رو می خوانی،اگر هم برابر نبود،5بایت قبلی رو به عقب شیفت می دی،(بایت اول حذف میشه و 4 بایت میمونه )، حالا بایت بعدی رو می خونی و جستجو رو روی 5 بایت جدید انجام میدی.

موفق باشی

فایل حتماً باید به صورت متنی خونده بشه . چون قراره از این راه یک کلمه عبور(رشته) رو به محتوای فایل تزریق کنیم . در واقع با این روش میشه روی هر فایلی پسورد گذاشت .

قبلاً در VB این کار رو انجام دادم :
http://www.m8spy.blogfa.com/post-3.aspx

SMRAH1
چهارشنبه 17 مهر 1387, 06:33 صبح
در مورد فراِیند تغییر در بایت های فایل اگر کمی توضیح بدی ،احتمالا می شه به جای تبدیل داده های بایتی به رشته (که امکان پذیر نیست) کلمه عبور رو تبدیل به بایت داده ای کرد و عملیات تلفیق رو انجام داد.

مهران رسا
پنج شنبه 18 مهر 1387, 00:51 صبح
در مورد فراِیند تغییر در بایت های فایل اگر کمی توضیح بدی ،احتمالا می شه به جای تبدیل داده های بایتی به رشته (که امکان پذیر نیست) کلمه عبور رو تبدیل به بایت داده ای کرد و عملیات تلفیق رو انجام داد.

با توجه به راهنمایی شما آیا میشه نتیجه گرفت که باز کردن یک فایل اجرایی به صورت متنی (بارگزاری محتوای متنی فایل های اجرایی) در #C غیر ممکن هست ؟ :متفکر: یعنی هیچ راهی نیست ؟!

حتی اگه بخوایم از روشی که ذکر کردید استفاده کنیم باز هم یک مشکل وجود داره . اون هم مشکل در سرعت بارگزاری Byte ها هست . مخصوصاً در فایل هایی با حجم بیشتر از 10 مگابایت !

SMRAH1
پنج شنبه 18 مهر 1387, 05:12 صبح
دوست من این کار هم توی #C و هم توی خیلی از زبونها غیر ممکنه.نه به خاطر ضعف زیان ،به خاطر عدم یکی بودن این دو مفهوم.
در ادامه توضیحاتی می نویسم که با اینکه مطمئنم می دونید (قصدم تکرار مکررات نیست) ولی برای اینکه بحث درست هدایت بشه،بهتره تکرارش کنم.

در کامیوتر هر کاراکتر از 8 بایت تشکیل شده و هر بایت هم معادل یک کاراکتر (character) است ولی نکته مهم اینه که این مفهوم کاراکتر با مفهوم حرف (الفبایی) که ما معمولا معادل می گیریم،یکی نیستند.مثلا ما در کامپیوتر یک کاراکتر داریم با مقدار صفر (0) که توی زبانهای C و ++C همون NULL است.اما این کاراکتر معادل هیچ حرف الفبایی که نیست (این بماند)،نمی تونید توی یک رشته (متنی) بیاریدش چون همه چیز بهم می ریزه (یکم جای بحث داره ولی در این رابطه ادامه نمی دهم).از این کاراکترها کم نیستند،مثلا کاراکتر 1 تا 9 یا 255 و .... برخی کاراکتر های دیگر.در مقابل کاراکتر هایی هستند که معادل الفبا هستند.مثلا کاراکتر65 معادل A و کاراکتر 97 معادل a و ....به همین دلیل است که فایل ها را همواره به دو دسته تقسیم می کنند.فایلهای باینری و فایل های متنی (Text) در دسته دوم تضمین شده است که کاراکتر های غیر متنی (که تاکید کردم ممکن است دردسر ساز باشند) وجود ندارند.حالا آیا شما می توانید در فایل مورد نظر خود مطمئن باشید که کاراکتر غیر مجاز متنی ندارد؟
در این میان باید حساب برخی زبانها (مثل c) رو جدا کرد (قدرت این زبانها هم در همین موارد کوچک اما مهم هستند).چون توی اونها، اساس از کاراکتر هست و یک رشته (متنی)، ترکیب چند کاراکتر (اگر به عنوان رشته با اونها برخود کنیم باید از قوانین که کمی در موردش بحث شد پیروی کنند مثلا آخرین کاراکتر رشته مقدار NULL است : این خودش یکی از همان دردسر ها است) ولی اگر به شکل آرایه ای از بایتها باشد،می توان هر کاری با آن کرد.

در این گونه نرم افزارها هم (که مثال زده بودید) قطعا باید برنامه با بایت برخورد کند نه با رشته ها (مگر فایلهای متنی).به همین دلیل درخواست کردم که فرآیند مورد نظرتون رو بفرمایید تا صریح تر راهنماییتون کنم.

اما خواندن بایت به بایت،همونطور که نوشته بودید،کار زمانبری است.یکی از این راهکار ها خواندن بایت ها، با حجم بالا تر است (مثلا 1 مگا بایت یک مگا بایت و ...)در این حالت با توجه به نکاتی مثل کاهش زمان خواندن هارد (به خاطر کمتر حرکت نمودن هد) و ... سرعت اجرا بالا می ره.

موفق باشید

مهران رسا
جمعه 19 مهر 1387, 01:00 صبح
ممنون از توضیحتون . ولی من هنوز متقاعد نشدم .

ببینید کاراکتری مثل ے جز هیچیک از حروف الفبا نیست ولی یک رشته مجاز محسوب میشه . به این دلیل که شما الآن دارید اون در مرورگرتون مشاهده می کنید .
نمونه بارز تر اون Notepad ویندوز ! (پسوند فایل exe ای رو به txt تغیرر داده و روی اون دابل کلیک کنید)




در این گونه نرم افزارها هم (که مثال زده بودید) قطعا باید برنامه با بایت برخورد کند نه با رشته ها (مگر فایلهای متنی).

بازهم میگم؛ برنامه ای که نام بردم دقیقاً فایل های اجرایی و یا غیر اجرایی (مثل jpg - avi - 3gp - pdf ) رو به صورت متنی باز کرده و درون یک متغیر رشته ای قرار میده :



Strx$ = Space(FileLen("C:\File.exe"))
Open "C:\File.exe" For Binary As #1
Get #1, , Strx$
Close
FileText = Strx$


از دوستان عزیز ، کسی نظری نداره ؟

SMRAH1
شنبه 20 مهر 1387, 08:09 صبح
سلام

دوست من،شما در حال مخلوط کردن برخي مفاهيم و نکات هستيد که در عين ارتباط، با اين مشکل بي ارتباطتند.براي نمونه کاراکتري رو که گفته ايد در مرورگر ديده ميشه،درسته ولي اين به خاطر استفاده از Character Encoding به کار رفته در اين صفحات است.انواع Character Encoding که پيش پا افتاده ترين آنها همان ASCII است و يونيکد، CodPage و UFT-8 و Utf-16 و ... بسيار زيادند (شايد معروفترينشان براي کاربران ويندوز همين ها است).با ايجاد اختلاط در اين مفاهيم ،از مسير دور مي شويد.متاسفانه بحث در اين رابطه جايگاهش در اين تاپيک نيست ولي اطلاع در اين رابطه (ساختار و نحوه استفاده و ...) بسيار لازم است.مثلا کارکتر هاي يونيکد به صورت دو بايتي (بر عکس ASC که به شکل تک بايتي تفسير مي شود)،تفسير مي شوند.در نتيجه گستره وسيعي را در بر مي گيرند.به همين دليل ما در برخي برنامه ها آنها را مي بينيم و .....برخي تفاوت ها در نرم افزار ها هم از همين جا ناشي مي شوند (مثال Photo SHop و Photo Shop ME که براي خاورميانه يا به طور کلي خطوط راست به چپ است).
اما تصميم دارم به برنامه VB که نوشته ايد بپردازم تا شايد کمي اين ابهام ها روشن شود (البته بي ربط به برخي نکات بالا نيست).من کد شما را تغيير دادم و برنامه اي را براي استفاده با آن طراحي کد به شکل زير (کد،برنامه و مثال ها در فايل پيوست است):


Private Sub Command1_Click()
ShowFileInfo "1.1"
End Sub

Private Sub Command2_Click()
ShowFileInfo "2.2"
End Sub

Private Sub Command3_Click()
ShowFileInfo "3.3"
End Sub

Private Sub ShowFileInfo(fileName1 As String)
Dim str As String

fileName2 = App.Path & "\" & fileName1
fileNameSave = fileName2 & ".Rep"

Strx$ = Space(FileLen(fileName2))
Open fileName2 For Binary As #1
Get #1, , Strx$
Close
str = Strx$
str = Replace(str, "B", "C")
MsgBox "File name : " & fileName1 & vbCrLf & _
"File size : " & FileLen(fileName2) & vbCrLf & _
"len Strx$ : " & Len(Strx$) & vbCrLf & _
"Strx$ : " & Strx$ & vbCrLf & _
"Replaced : " & str & vbCrLf
Strx$ = Replace(Strx$, "B", "C")
Open fileNameSave For Binary As #2
Put #2, , Strx$
Close

End Sub

اين برنامه در VB6 نوشته شده است و سه فايل را با نامهاي 1.1 و 2.2 و 3.3 باز کرده و داده هاي آن ها را خوانده (به همان طريقي که نوشته ايد) و اطلاعاتي شامل نام فايل، طول فايل، طول متغير رشته اي (!) و مقدار درون اين متغير و در نهايت رشته حاصل از جانشيني حرف C به جاي B نمايش مي دهد.بي مناسبت نيست که اين فايلها را در Notepad نيز ببينيد.فايل 1.1 شامل سه بايت است که به ترتيب کد ها 65 و 65 و 66 هستند (حروف A و A و B).فايل 2.2 همانند فايل 1.1 است با اين تفاوت که بايت دوم به جاي 65،مفدار 0 دارد.فايل سوم هم 10 بايتي است که در واقع کلمه «ايران» را با يونيکد نوشته است.در ضمن برنامه پس از ديدن هر فايل، يک فايل همنام فايل مبدا با پسوند Rep مي سازد که رشته حاصل از Replace درون فايل قرار دارد.
خروجي نمايش اين سه فايل در تصوير زير پيوست شده است.
همانطور که مي بيند در فايل 1.1 همه چيز درست است ولي در فايل 2.2 عملا از بايت دوم (که صفر است) ديده نيم شود (هر چند عمليات جانشيني به موفقيت انجام مي شود و در فايل ذخيره مي شود) جالب اينجا است که اگر اين فايل را با Notepad ببينيد به جاي کاراکتر 0 عملا کاراکتر SPACE را نمايش مي دهد (چون کاراکتر 0 خروجي ندارد).فايل سوم هم به جاي نمايش «ايران» کاراکتر هاي ديگري را نمايش مي دهد.
حالا سئوال اين است که برنامه چرا فايلها را درست مي خواند و جانشين مي کند.جواب اين است که برنامه فايل Text نمي خواند بلکه فايل باينري مي خواند (For Biynary) در نتيجه دستور Get کار خود را متناسب با خواندن فايل باينري انجام مي دهد.خوب چرا آن را درون يک متغير رشته اي مي ريزد؟چون شما قبل از خواندن به اندازه مورد نياز فضا براي اين متغير در نظر گرفته ايد.به عبارت ديگر اين برنامه يک فايل باينري را باز مي کند و اطلاعات آن را به شکل باينري در حافظه اي که شما مشخص کرده ايد،مي ريزد.براي اينکه دقيقا متوجه اين موضوع شويد که متغير، عملا رشته اي نيست کافيست به تصوير زمينه براي فايل 2.2 توجه کنيد که متغير رشته معادل چيست.(تمام بايت ها را نشان نمي دهد، حتي بايت آخر يعني B را که مي شود نمايش داد. به عبارت ديگر در عمل اين متغير داراي 1 بايت به عنوان رشته است).خوب پس چرا Replace کارش را روي تمام بايت ها انجام مي دهد؟خيلي ساده است.در VB6،در مورد متغيره اطلاعاتي ذخيره مي شود که توضيحاتي در رابطه با آن متغير در اختيار کامپايلر مي گذارد.(يه جايي خوانده بودم که هر متغير رشته اي 11 بايت بيشتر از طولي که کار بر فکر مي کند دارد که اطلاعاتي نظير مکان دقيق در حافظه و طول و ... را دارد.البته الان روي اين مطالب مطمئن نيستم ولي کليت مطلب همين است).در نتيجه تابع Replace يک متغير [رشته اي] با طول فايل مذکور دريافت و براي تک تک کاراکتر ها اقدام به جانشيني مي کند.به عبارت ديگر حتي کاراکتر 0 را نيز مي توان جانشين کرد (چون عملا به شکل بايتي برخورد مي کند). هر چند که در MSDN راهکار هايي مثل :


Sub WriteNewTextFile()
Dim characterArray() As Byte
Dim fileLen As Long
Dim strOrigFile As String
Dim strNewFile As String
Dim MyString As String
Dim fs As Object
'Change the path and the names of the files according to your requirement.
strOrigFile = "<Full path of your original text file>"
strNewFile = "<Full path of the new text file>"

Set fs = CreateObject("Scripting.FileSystemObject")
If (fs.FileExists(strOrigFile)) Then

'Open the file and obtain the length
Open strOrigFile For Binary As #1
fileLen = LOF(1)

'Read the file
ReDim characterArray(fileLen) As Byte
Get #1, , characterArray
Close #1

'The problem with the file occurs because the file contains null values that are embedded
Dim i As Long

For i = 1 To fileLen
'If the character is a null value, change it to a blank space like Notepad does
If (characterArray(i) = &H0) Then
characterArray(i) = &H20
End If
Next i

'Write the replacement file
Open strNewFile For Binary As #1
Put #1, , characterArray
Close #1

MsgBox "Completed"
Else
MsgBox "Provide valid path of the text file"
End If
End Sub

را پيشنهاد مي دهد.(در اين کد رسما اعلام مي کنيم که يک آرايه اي از بايت ها را در حال بارگذاري هستيم).

اما در سي شارپ انواع به شدت کنترل مي شوند و هرگونه عملياتي که با نوع مفروض مغايرت داشته باشد منتفي است.به همين منظور بايد حتما رسما يک آرايه اي از بايت ها بار کنيم. نه اينکه يک رشته رو بار کنيم و بعد از کامپايلر يا توابع بخواهيم با اينها همانند يک آرايه برخود کنند.به عبارت ديگر از کلاس System.IO.BinaryReader براي خواندن بايت ها استفاده کني و بايت ها را جانشين کني.در نهايت هم با System.IO.BinaryWriter انها را بنويسي.

اميدوار توانسته باشم تفاوت هاي درون سي شارپ و VB6 رو توضيح داده باشم.

موفق باشيد

Mehdi Asgari
شنبه 20 مهر 1387, 10:57 صبح
حق با SMRAH1 هست.
تو خانوادۀ C ، کاراکتر صفر یعنی NULL ، یعنی End of string . شما نمی تونید رشته ای حاوی کاراکتر صفر داشته باشید.
فایل exe مدنظرتون رو با یک Hex Editor باز کنید (به بایت های 00 توجه کنید)
http://i35.tinypic.com/2s15dm1.jpg

مهران رسا
شنبه 20 مهر 1387, 22:29 عصر
باز هم ممنون از توضیحاتتون .

پس به این نتیجه رسیدیم که در #C نمیشه مثل VB مستقیماً فایل رو به صورت باینری در یک متغیر رشته ای ذخیره کرد .

در ضمن یک نکته جالب دیگه در مورد VB بد نیست بدونید که بعد از انجام عملیات Replace فایل اجرایی رو به صورت ترتیبی (Output) هم که بنویسیم باز هم سالم و قابل استفاده هست .

و مورد آخر اینکه کنترل richTextBox در #C دقیقاً مثل Notepad میتونه محتوای متنی یک فایل اجرایی رو نشون بده . ولی باز هم بر خلاف VB ، بعد از اینکه فایل رو با StreamWriter (ترتیبی) می نویسیم قابل استفاده نیست .

متشکرم !