整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          是時候為你的C#程序進行代碼混淆

          是時候為你的C#程序進行代碼混淆

          不管是C#還是Java,都是可以通過反編譯工具,進行反編譯后查看源碼,這個源碼雖然不是真正意義的源碼,但和真正源碼的相差不是很大.如果是單純的Web還好一些.因為只需要部署到服務器上,也很少人能看到部署文件.所以相對要好一些.如果是C#做客戶端的話,是需要安裝到客戶機上的.所以還是需要對程序做一下處理,對程序代碼進行代碼混淆.

          這里主要使用Obfuscator這個工具,Obfuscator是源碼開源.且也是國人Lex Li(已經(jīng)出國)所寫.

          在VS中如何使用Obfuscator

          1.在Nuget中,搜索Obfuscator,并進行安裝

          在Nuget瀏覽器中,搜索Obfuscator

          2.創(chuàng)建obfuscar.xml,并設置該文件為較新復制

          在屬性中,設置文件較新復制

          3. 在obfuscar.xml中指定配置信息

          <?xml version="1.0" encoding="utf-8" ?>
          <Obfuscator>
            <!--輸入路徑-->
            <Var name="InPath" value="." />
            <!--輸出路徑:加密混淆過的路徑-->
            <Var name="OutPath" value=".\Obfuscator_Output" />
            <!--混淆代碼的參數(shù)-->
            <Var name="ReuseNames" value="false" />
            <Var name="HideStrings" value="false" />
            <Var name="KeepPublicApi" value="false" />
            <Var name="HidePrivateApi" value="true" />
            <!--要混淆的模塊-->
            <Module file="$(InPath)\ConsoleApp2.exe" />
          </Obfuscator>
          參數(shù)信息,可以看這里: https://docs.obfuscar.com/getting-started/configuration.html

          4.在程序生成之后調(diào)用Obfuscar.通過VS的生成事件實現(xiàn).

          在VS中生成后事件,調(diào)用Obfusacr 并加載obfuscar.xml

          5.在Obfuscator_Output目錄,通過反編譯工具JustDecompilte查看混淆過的程序.

          使用反編譯工具JustDecompilte查看混淆過的代碼

          在命令行中使用Obfuscator

          Obfuscator可以不在VS中直接使用,Obfuscator是一個單純的代碼混淆工具. 上邊說過Obfuscator代碼是開源的.

          在GitHub項目地址: git@github.com:obfuscar/obfuscar.git
          在Gitee項目地址: https://gitee.com/junweihuang_admin/obfuscar.git

          因為Gitee速度要快于GitHub,如果Gitee上有的話,還是優(yōu)先使用Gitee. 如果Gitee上面沒有的話,就得去Github上.打開Obfuscar.sln解決方案.進行編譯.發(fā)現(xiàn)是無法編譯成功的.發(fā)現(xiàn)Obfuscator依賴Baml項目中.

          在Baml項目中,發(fā)現(xiàn)這幾個不存在的.

          發(fā)現(xiàn)Baml項目中,有4個文件不存在

          在Obfuscator項目中的Obfuscator.cs發(fā)現(xiàn)ILSpy.BamlDecompiler.Baml命名:

          發(fā)現(xiàn)了ILSpy.BamlDecompiler.Baml這個命名空間

          便懷疑是不是缺的這幾個文件在IlSpy中呀!于是便把IlSpy源碼下載到本地,最終找到了這幾個文件.將這幾個文件拷貝到Baml項目中,嘗試編譯,果真是編譯成功了.

          生成后的目錄:

          Obfuscar代碼混淆工具,只需要將要混淆的程序放入Input路徑下,在obfuscar.xml修改指定,雙擊run.bat就可以了

          Obfuscar.Console.exe使用:

          1. 將要混淆的程序集放入Input目錄中
          2. 修改obfuscar.xml指定要混淆的程序集(exe或dll)
          3. 雙擊run.bat

          文分享的是一個動畫效果源碼,演示JS代碼是如何被加密的。

          先看效果:

          一般我們在進行JS加密時,提交原始代碼,緊接著就直接得到了加密代碼,混淆加密過程是黑盒狀態(tài),是不被我們知道的。

          這個動畫,用慢放的效果,逐幀演示了JS代碼在進行混淆加密時發(fā)生的變化。

          比如:變量名變短、回車換行消失、空格刪除、消除注釋、函數(shù)調(diào)用變成自執(zhí)行函數(shù)。

          注:動畫演示的是JShaman專業(yè)版使用部分功能對JS代碼進行混淆加密的效果。

          下面給出這個動畫完整源碼,保存為html文件即可使用:

          <h2>動畫演示:JShaman是怎樣對JS代碼混淆加密的</h2>
          <button onclick="mini_change();">開始</button><br>
          <br>
          <textarea id="js_code" style="width:800px; height:200px;font-size:19px;">
          function get_copyright(){
              var domain="JShaman專注于JS代碼混淆加密";
              var from_year=2017;
              var the_copyright="(c)" + from_year + "-" + (new Date).getFullYear() + "," + domain;
              return the_copyright;
          }
          //輸出信息
          console.log(get_copyright());
          </textarea>
          <br>
          注:演示的是JShaman專業(yè)版部分效果
          <script>
          
              var index=0;
              var js_code_textarea=document.getElementById("js_code");
              var change_matrix=[
                  ["\n",""],
                  ["    ",""],
                  ["var domain","var _"],
                  ["\n",""],
                  ["    ",""],
                  ["var from_year","var _2"],
                  ["\n",""],
                  ["    ",""],
                  ["var the_copyright","var _3"],
                  ["from_year","_2"],
                  ["\n",""],
                  ["    ",""],
                  ["\n",""],
                  ["the_copyright","_3"],
                  ["domain","_"],
                  ["\n",""],
                  ["//輸出信息",""],
                  ["\n",""],
                  ["function get_copyright(){",""],
                  ["}",""],
                  ["get_copyright()","function(){"+`var _="JShaman專注于JS代碼混淆加密";var _2=2017;var _3="(c)" + _2 + "-" + (new Date).getFullYear() + "," + _;return _3;`+"}()"],
                  [`var _="JShaman專注于JS代碼混淆加密";var _2=2017;var _3="(c)" + _2 + "-" + (new Date).getFullYear() + "," + _;return _3;`,""],
              ]
              
              function mini_change(){
                  js_code_textarea.value=js_code_textarea.value.replace(change_matrix[index][0], change_matrix[index][1]);
                  index++;
                  console.log(index[0]);
          
                  if(index >change_matrix.length-1){
                      console.log("執(zhí)行");
                      eval(js_code_textarea.value);
                      alert("演示完成");
                      return;
                  }else{
                      setTimeout(mini_change,1000);
                  }
              }
          </script> 

          這段代碼中,應用了一些不錯的JS技巧,參考修改,也可以用來做其它文本演示動畫。

          們已經(jīng)學到很多反爬機制以及相應的反反爬策略。使用那些手段,其實已經(jīng)完全可以完成絕大多數(shù)的爬蟲任務。但是,還是有極個別的情況下,會出現(xiàn)諸如 JS 加密和 JS 混淆之類的高深反爬機制。

          如果不幸遇到這種反爬機制,一個明智之舉是給站長點個贊,然后恭恭敬敬選擇放棄,去別的地方找數(shù)據(jù)。

          當然,還是那句話,我們可以選擇不爬,但是對付 JS 加密和 JS 混淆的方法卻不可以不會。

          這里就以中國空氣質(zhì)量在線檢測平臺為例,介紹 JS 加密和 JS 混淆的實現(xiàn)和破解方法。

          要爬取的網(wǎng)站:https://www.aqistudy.cn/html/city_detail.html

          這個網(wǎng)站正在升級,所以頁面無法正常顯示。這也意味著這個網(wǎng)站本身的 JS 解密是有問題的(如果沒問題就能顯示了),所以最后我們并不能完全解析出數(shù)據(jù)來。雖然如此,這個網(wǎng)站仍然是學習 JS 加密和 JS 混淆的相當不錯的平臺。

          閑話少說,開始干活!

          首先瀏覽器打開網(wǎng)頁,并打開調(diào)試臺的抓包工具。修改查詢條件(城市的名稱 + 時間范圍),然后點擊查詢按鈕,捕獲點擊按鈕后發(fā)起請求對應的數(shù)據(jù)包。點擊查詢按鈕后,并沒有刷新頁面,顯然發(fā)起的是 ajax 請求。該請求就會將指定查詢條件對應的數(shù)據(jù)加載到當前頁面中(我們要爬取的數(shù)據(jù)就是該 ajax 請求請求到的數(shù)據(jù))。

          分析捕獲到的數(shù)據(jù)包

          • 提取出請求的 url:https://www.aqistudy.cn/apinew/aqistudyapi.php
          • 請求方式:post
          • 請求參數(shù):d: 動態(tài)變化一組數(shù)據(jù)(且加密)
          • 響應數(shù)據(jù):是加密的密文數(shù)據(jù)

          該數(shù)據(jù)包請求到的是密文數(shù)據(jù),為何在前臺頁面顯示的卻是原文數(shù)據(jù)呢?

          原來,在請求請求到密文數(shù)據(jù)后,前臺接受到密文數(shù)據(jù)后使用指定的解密操作(JS 函數(shù))對密文數(shù)據(jù)進行了解密操作,然后將原文數(shù)據(jù)顯示在了前臺頁面。

          接下來的工作流程:

          首先先處理動態(tài)變化的請求參數(shù),動態(tài)獲取該參數(shù)的話,就可以攜帶該參數(shù)進行請求發(fā)送,將請求到的密文數(shù)據(jù)捕獲到。

        1. 將捕獲到的密文數(shù)據(jù)找到對應的解密函數(shù)對其進行解密即可。
        2. 【重點】需要找到點擊查詢按鈕后對應的 ajax 請求代碼,從這組代碼中就可以破解動態(tài)變化的請求參數(shù)和加密的響應數(shù)據(jù)對應的相關操作。
        3. 找 ajax 請求對應的代碼,分析代碼獲取參數(shù) d 的生成方式和加密的響應數(shù)據(jù)的解密操作。直接在頁面中,并沒有辦法直接找到發(fā)送 ajax 請求的函數(shù)的,因為它以及被封裝到別的文件中了。我們可以基于火狐瀏覽器定位查詢按鈕綁定的點擊事件。
        4. 抽絲剝繭,首先從 getData 函數(shù)實現(xiàn)中找尋 ajax 請求對應的代碼。在該函數(shù)的實現(xiàn)中沒有找到 ajax 代碼,但是發(fā)現(xiàn)了另外兩個函數(shù)的調(diào)用,getAQIData()getWeatherData()。ajax 代碼一定是存在于這兩個函數(shù)實現(xiàn)內(nèi)部。

          另外,這里記住一個參數(shù),type==’HOUR‘,它的含義是查詢時間是以小時為單位。這個參數(shù)我們后來會用到。

          接下來我們就去分析 getAQIData()getWeatherData(),爭取能夠找到 ajax 代碼。

          我們找到這兩個函數(shù)的定義位置,還是沒有找到 ajax 請求代碼。不過我們卻發(fā)現(xiàn)它們同時調(diào)用了另外一個函數(shù),getServerData(method,param,func,0.5)。它的參數(shù)的值可以為:

          • method 可以是 ‘GETCITYWEATHER’ 或者 ‘GETDETAIL’
          • params 的值是 {city, type, startTime, endTime},也就是查詢條件
          • func 是一個匿名函數(shù),看樣子是在處理數(shù)據(jù)。

          下一步當然就要找 getServerData 函數(shù)了,看看那個函數(shù)里面有沒有我們一致想要的發(fā)送 ajax 請求的代碼。

          我們嘗試著在頁面中搜索,卻找不到這個函數(shù)。很顯然,它是被封裝到其他 js 文件中了。這時,我們可以基于抓包工具做全局搜索。

          好消息是,我們順利找到了 getServerData 函數(shù)!壞消息是,這貨長得一點也不像是函數(shù)。

          這是因為,這段 JS 函數(shù)代碼被加密的。這種加密的方式,我們稱為 JS 混淆。

          JS 混淆,也就是對核心的 JS 代碼進行加密。

          JS 反混淆,則是對 JS 加密代碼進行解密。

          接下來我們要做的,就是 JS 反混淆,讓這段我們看不懂的東西,顯現(xiàn)出廬山真面目。

          我們用的方法十分簡單粗暴,也就是暴力破解。使用這個網(wǎng)站就可以實現(xiàn)對 JS 混淆的暴力破解:https://www.bm8.com.cn/jsConfusion/

          將 getServerData 函數(shù)所在的那一整行代碼都復制過來,粘貼到這個網(wǎng)址的文本輸入框中,然后點擊 開始格式化 即可:

          終于,我們看到了 getServerData 的代碼,并且在其中發(fā)現(xiàn)了發(fā)送 ajax 的請求:

          function getServerData(method, object, callback, period) {
              const key=hex_md5(method + JSON.stringify(object));
              const data=getDataFromLocalStorage(key, period);
              if (!data) {
                  var param=getParam(method, object);
                  $.ajax({
                      url: '../apinew/aqistudyapi.php',
                      data: {
                          d: param
                      },
                      type: "post",
                      success: function (data) {
                          data=decodeData(data);
                          obj=JSON.parse(data);
                          if (obj.success) {
                              if (period > 0) {
                                  obj.result.time=new Date().getTime();
                                  localStorageUtil.save(key, obj.result)
                              }
                              callback(obj.result)
                          } else {
                              console.log(obj.errcode, obj.errmsg)
                          }
                      }
                  })
              } else {
                  callback(data)
              }
          }

          從這段代碼中,我們不難得出下面這幾個信息:

          • ajax 請求成功后獲得到的 data 是加密的響應數(shù)據(jù)(就是我們最開始通過抓包工具看到的那一串神秘的相應字符串),通過 decodeData(data) 函數(shù),可以將加密的數(shù)據(jù)解密成我們需要的明文數(shù)據(jù)。
          • 發(fā)送請求時攜帶的參數(shù),也就是 d 對應的值 param 是通過 getParam(method, object) 函數(shù)返回動的態(tài)變化的請求參數(shù)。這兩個參數(shù)我們前面也分析過:參數(shù) method 可以是 ‘GETCITYWEATHER’ 或者 ‘GETDETAIL’參數(shù) object 則為 {city, type, startTime, endTime},是我們的查詢條件我們當然還可以繼續(xù)最終下去,刨根問題找到它們究竟是通過什么方式進行加密和解密的。然后,使用 Python 代碼,重復這個加密和解密的過程,完成請求數(shù)據(jù)的生成和響應數(shù)據(jù)的解析過程。

          但是我們并不打算這么做。因為再繼續(xù)深挖下去,難度將會陡然增加。此時我們已經(jīng)很疲憊了,如果繼續(xù)下去恐怕要瘋掉。而且,JavaScript 和 Python 畢竟是兩種語言,它們之間的方法和各種包都不相同。JavaScript 能實現(xiàn)的,Python 未必能夠輕松完成。所以重新寫一個加密和解密的腳本,并不是明智之舉。

          更好的解決方案是,我們提供請求的明文數(shù)據(jù),通過網(wǎng)站自己的 JS 代碼進行加密,得到加密的請求參數(shù)。使用這個參數(shù),我們發(fā)送請求給服務端。拿到加密的響應數(shù)據(jù)后,再通過網(wǎng)站的 JS 代碼進行解密。

          也就是說,我們接下來需要做的就是要調(diào)用兩個 JS 函數(shù) decodeData 和 getParam,并拿到返回結果即可。

          現(xiàn)在的問題是,在 Python 程序中如何調(diào)用 JS 函數(shù)呢?

          這就涉及到一個新的概念:JS 逆向。JS 逆向,也就是在 Python 中調(diào)用 JS 函數(shù)代碼。

          能夠?qū)崿F(xiàn) JS 逆向的方式有兩種:

          1. 手動將 JS 函數(shù)改寫稱為 Python 函數(shù)并執(zhí)行。
          2. 這種方法我剛剛談過了,并不現(xiàn)實。因為 JS 能實現(xiàn)的,Python 未必能夠輕易實現(xiàn)。而且畢竟還要重寫函數(shù),比較麻煩。
          3. 使用固定模塊,實現(xiàn)自動逆向(推薦)。
          4. 一個很好用的實現(xiàn) JS 逆向的 Python 庫 是 PyExecJS。
          5. PyExecJS 庫用來實現(xiàn)模擬 JavaScript 代碼執(zhí)行獲取動態(tài)加密的請求參數(shù),然后再將加密的響應數(shù)據(jù)帶入 decodeData 進行解密即可。
          6. PyExecJS 需要在本機安裝好 nodejs 的環(huán)境。
          7. PyExecJS 的安裝:
          pip install PyExecJS

          接下來,我們就可以生成加密的請求數(shù)據(jù)了。

          首先,把我們解析出來的那串代碼保存到本地,比如名為 code.js 的文件中。在里面我們補充一個函數(shù),比如名字叫 getPostParamCode,用來發(fā)起我們的數(shù)據(jù)請求。之所以這樣做是因為使用 PyExecJS 調(diào)用 JS 函數(shù)時,傳入的參數(shù)只能是字符串。而 getParam 方法的參數(shù)需要用到 JS 的自定義對象。

          我們只需在 code.js 中加上下面的代碼即可:

          function getPostParamCode(method, type, city, start_time, end_time) {
              var param={};
              param.type=type;
              param.city=city;
              param.start_time=start_time;
              param.end_time=end_time;
              return getParam(method, param)
          }

          然后,使用 PyExecJS 調(diào)用里面的 getParam 方法,將我們的請求數(shù)據(jù)加密:

          # 模擬執(zhí)行decodeData的js函數(shù)對加密響應數(shù)據(jù)進行解密
          import execjs
          import requests
          
          node=execjs.get()
          
          # 請求參數(shù)
          method='GETCITYWEATHER'
          type='HOUR'
          city='北京'
          start_time='2020-03-20 00:00:00'
          end_time='2020-03-25 00:00:00'
          
          # 編譯js代碼
          file='code.js'    # js代碼的路徑
          ctx=node.compile(open(file, encoding='utf-8').read())
          
          # 將請求數(shù)據(jù)加密
          encode_js=f'getPostParamCode("{method}", "{type}", "{city}", "{start_time}", "{end_time}")'
          params=ctx.eval(encode_js)
          
          # 使用加密的參數(shù),發(fā)起post請求
          url='https://www.aqistudy.cn/apinew/aqistudyapi.php'
          response_text=requests.post(url, data={'d': params}).text
          
          # 將響應數(shù)據(jù)解密
          decode_js=f'decodeData("{response_text}")'
          decrypted_data=ctx.eval(decode_js)    # 如果順利,返回的將是解密后的原文數(shù)據(jù)
          print(decrypted_data)    # 執(zhí)行會報錯:目前頁面中沒有數(shù)據(jù)。解密函數(shù)只是針對頁面中原始的數(shù)據(jù)進行解密。

          自此,我們完成了 JS 加密和 JS 混淆的處理。這里我們總結一下這幾個概念:

          • JS 加密,也就是通過 JS 代碼,將數(shù)據(jù)進行加密處理,將明文數(shù)據(jù)變成密文數(shù)據(jù)。如果不能將其解密,密文數(shù)據(jù)將毫無用處。
          • JS 解密:通過 JS 代碼,將加密的數(shù)據(jù)解密,也就是將密文數(shù)據(jù)解析成明文數(shù)據(jù)。JS 解密是 JS 加密的逆過程。
          • JS 混淆:將 JS 代碼(比如 JS 函數(shù))本身進行加密。
          • JS 反混淆:將加密了的 JS 代碼解密成常規(guī)的 JS 代碼。通常直接使用暴力破解即可。
          • JS 逆向(重要):通過 Python 代碼調(diào)用 JS 的函數(shù)。

          附,ajax 請求的各個數(shù)據(jù)的含義:


          主站蜘蛛池模板: 国产精品亚洲产品一区二区三区 | 香蕉久久ac一区二区三区| 免费看无码自慰一区二区 | 亚洲色精品VR一区区三区| 久久久久久免费一区二区三区 | 精品女同一区二区| 中文字幕在线无码一区二区三区| 国产综合一区二区在线观看| 亚洲视频在线观看一区| 成人国产精品一区二区网站| 国产伦理一区二区| 日韩一区二区精品观看| 成人免费视频一区二区三区| 日本一区二区免费看| V一区无码内射国产| 亚洲AV日韩综合一区| 麻豆一区二区在我观看| 在线精品动漫一区二区无广告| 国产乱码精品一区二区三区四川人 | 无码视频一区二区三区| 亚洲视频一区在线| 日韩人妻无码一区二区三区久久 | 国产suv精品一区二区33| 国产成人无码精品一区在线观看| 国产成人一区二区三区| 无码精品尤物一区二区三区| 人妻少妇精品视频一区二区三区 | 久久精品一区二区| 国产爆乳无码一区二区麻豆 | 国产短视频精品一区二区三区| 日韩人妻无码一区二区三区综合部| 日本一区二区三区四区视频| 国产高清视频一区二区| 麻豆精品一区二区综合av| 免费人妻精品一区二区三区| 国产激情一区二区三区 | 亚洲一区二区三区影院 | 色系一区二区三区四区五区| 日韩十八禁一区二区久久| 久久精品中文字幕一区| 精品国产亚洲一区二区三区|