此文是接著 《BurpSuite插件開發指南之 API 上篇》 所寫,此篇中將要介紹的 API 和上篇有著緊密的聯系,所以建議讀者可以將上下篇作為一個整體去看待。
《BurpSuite 插件開發指南》系列文章如下:
public interface IMessageEditor
此接口被用于使用 Burp 的 HTTP 消息編輯框的實例提供擴展功能,以便擴展插件可以在它自己的 UI 中使用消息編輯框,擴展插件可以通過調用 IBurpExtenderCallbacks.createMessageEditor() 獲得此接口的實例。
此接口提供了以下方法:
#!java
// 此方法返回了編輯器的 UI 組件,擴展插件可以將其添加到自己的 UI 中
java.awt.Component getComponent()
// 此方法用于獲取當前已顯示的消息,此消息可能已被用戶修改
byte[] getMessage()
// 此方法返回了用戶當前所選擇的數據
byte[] getSelectedData()
// 此方法用于決定當前的消息是否可被用戶修改
boolean isMessageModified()
// 此方法用于將一個 HTTP 消息顯示在編輯器中
void setMessage(byte[] message, boolean isRequest)
注: 此接口需要與 IMessageEditorTabFactory 等相關接口一起使用。
Demo code:
請見 IMessageEditorTabFactory 的實例代碼。
public interface IMessageEditorController
此接口被用于 IMessageEditor 獲取當前顯示的消息的細節。創建了 Burp 的 HTTP 消息編輯器實例的擴展插件可以有選擇的實現 IMessageEditorController接口,當擴展插件需要當前消息的其他信息時,編輯器將會調用此接口(例如:發送當前消息到其他的 Burp 工具中)。擴展通過 IMessageEditorTabFactory 工廠提供自定義的編輯器標簽頁,此工廠的 createNewInstance 方法接受一個由該工廠所生成的每一個標簽頁的IMessageEditorController 對象的引用,當標簽頁需要當前消息的其他信息時,則會調用該對象。
此方法提供了以下方法:
#!java
// 此方法用于獲取當前消息的 HTTP 服務信息
IHttpService getHttpService()
// 此方法用于獲取當前消息的 HTTP 請求(也有可能是一個響應消息)
byte[] getRequest()
// 此方法用于獲取當前消息的 HTTP 響應(也有可能是一個請求消息)
byte[] getResponse()
Demo code:
請見 IMessageEditorTabFactory 的實例代碼。
public interface IMessageEditorTab
擴展插件通過注冊 IMessageEditorTabFactory 工廠,此工廠的createNewInstance返回一個當前接口的實例,Burp 將會在其 HTTP 消息編輯器中創建自定義的標簽頁。
此接口提供了如下方法:
#!java
// 此方法返回當前顯示的消息
byte[] getMessage()
// 此方法用于獲取當前已被用戶選擇的數據
byte[] getSelectedData()
// 此方法返回自定義標簽頁的標題
java.lang.String getTabCaption()
// 此方法返回自定義標簽頁內容的組件
java.awt.Component getUiComponent()
// 此方法用于指示在顯示一個新的 HTTP 消息時,是否啟用自定義的標簽頁
boolean isEnabled(byte[] content, boolean isRequest)
// 此方法用于決定當前顯示的消息是否可被用戶修改
boolean isModified()
// 此方法可以顯示一個新的消息或者清空已存在的消息
void setMessage(byte[] content, boolean isRequest)
Demo code:
請見 IMessageEditorTabFactory 的實例代碼。
public interface IMessageEditorTabFactory
擴展可以實現此接口,并且可以調用 IBurpExtenderCallbacks.registerMessageEditorTabFactory() 注冊一個自定義的消息編輯器標簽頁的工廠。擴展插件可以在 Burp 的 HTTP 編輯器中渲染或編輯 HTTP 消息。
此接口提供了一個方法:
#!java
// Burp 將會對每一個 HTTP 消息編輯器調用一次此方法,此工廠必須返回一個新的 IMessageEditorTab 對象
IMessageEditorTab createNewInstance(IMessageEditorController controller, boolean editable)
Demo code:
#!java
package burp;
import java.awt.Component;
import java.io.PrintWriter;
public class BurpExtender implements IBurpExtender, IMessageEditorTabFactory{
public PrintWriter stdout;
public IExtensionHelpers helpers;
private IBurpExtenderCallbacks callbacks;
@Override
public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks){
this.stdout = new PrintWriter(callbacks.getStdout(), true);
this.callbacks = callbacks;
this.helpers = callbacks.getHelpers();
callbacks.setExtensionName("Her0in");
callbacks.registerMessageEditorTabFactory(this);
}
@Override
public IMessageEditorTab createNewInstance(
IMessageEditorController controller, boolean editable) {
// 返回 IMessageEditorTab 的實例
return new iMessageEditorTab();
}
class iMessageEditorTab implements IMessageEditorTab{
// 創建一個新的文本編輯器
private ITextEditor iTextEditor = callbacks.createTextEditor();
@Override
public String getTabCaption() {
// 設置消息編輯器標簽頁的標題
return "測試 MessageEditorTab";
}
@Override
public Component getUiComponent() {
// 返回 iTextEditor 的組件信息,當然也可以放置其他的組件
return iTextEditor.getComponent();
}
@Override
public boolean isEnabled(byte[] content, boolean isRequest) {
// 在顯示一個新的 HTTP 消息時,啟用自定義的標簽頁
// 通過 content 和 isRequest 也可以對特定的消息進行設置
return true;
}
@Override
public void setMessage(byte[] content, boolean isRequest) {
// 把請求消息里面的 data 參數進行 Base64 編碼操作
// 這里并未處理參數中沒有 data 時的異常
IParameter parameter = helpers.getRequestParameter(content, "data");
stdout.println("data = " + parameter.getValue());
iTextEditor.setText(helpers.stringToBytes(helpers.base64Encode(parameter.getValue())));
}
@Override
public byte[] getMessage() {
// 獲取 iTextEditor 的文本
return iTextEditor.getText();
}
@Override
public boolean isModified() {
// 允許用戶修改當前的消息
return true;
}
@Override
public byte[] getSelectedData() {
// 直接返回 iTextEditor 中選中的文本
return iTextEditor.getSelectedText();
}
}
}
加載上述代碼生成的插件后,會顯示自定義的標簽頁和文本編輯器。
注意:官網提供的自定義消息編輯器的代碼有誤!
public interface IParameter
此接口用于操控 HTTP 請求參數,開發者通過此接口可以靈活的獲取請求或響應里的參數。
#!java
// 此方法用于獲取參數名稱
java.lang.String getName()
// 此方法用于獲取在 HTTP 請求里面的最后一個參數的名稱
int getNameEnd()
// 此方法用于獲取在 HTTP 請求里面的第一個參數的名稱
int getNameStart()
// 此方法用于獲取參數類型,參數的類型在 IParameter 接口中有定義
byte getType()
// 此方法用于獲取參數的值
java.lang.String getValue()
// 此方法用于獲取最后一個參數的值
int getValueEnd()
// 此方法用于獲取第一個參數的值
int getValueStart()
Demo code:
#!java
package burp;
import java.io.PrintWriter;
import java.util.List;
public class BurpExtender implements IBurpExtender, IHttpListener{
public PrintWriter stdout;
public IExtensionHelpers helpers;
private IBurpExtenderCallbacks callbacks;
@Override
public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks){
this.stdout = new PrintWriter(callbacks.getStdout(), true);
this.callbacks = callbacks;
this.helpers = callbacks.getHelpers();
callbacks.setExtensionName("Her0in");
callbacks.registerHttpListener(this);
}
@Override
public void processHttpMessage(int toolFlag, boolean messageIsRequest,
IHttpRequestResponse messageInfo) {
// 獲取請求中的參數
if(messageIsRequest){
IRequestInfo iRequestInfo = helpers.analyzeRequest(messageInfo);
// 獲取請求中的所有參數
List<IParameter> iParameters = iRequestInfo.getParameters();
for (IParameter iParameter : iParameters) {
if(iParameter.getType() == IParameter.PARAM_URL)
stdout.println("參數:" + iParameter.getName() + " 在 URL中");
stdout.println("參數:" + iParameter.getName() + " 的值為:" + iParameter.getValue());
}
}
}
}
加載上述代碼生成的插件后,執行效果如下圖所示:
public interface IProxyListener
擴展可以實現此接口,并且可以通過調用 IBurpExtenderCallbacks.registerProxyListener() 注冊一個代理監聽器。在代理工具處理了請求或響應后會通知此監聽器。擴展插件通過注冊這樣一個監聽器,對這些消息執行自定義的分析或修改操作。
此接口提供了一個很常用的方法:
#!java
// 當代理工具處理 HTTP 消息時則會調用此方法
void processProxyMessage(boolean messageIsRequest, IInterceptedProxyMessage message)
Demo code:
#!java
package burp;
import java.io.PrintWriter;
public class BurpExtender implements IBurpExtender, IProxyListener{
public PrintWriter stdout;
public IExtensionHelpers helpers;
private IBurpExtenderCallbacks callbacks;
@Override
public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks){
this.stdout = new PrintWriter(callbacks.getStdout(), true);
this.callbacks = callbacks;
this.helpers = callbacks.getHelpers();
callbacks.setExtensionName("Her0in");
callbacks.registerProxyListener(this);
}
@Override
public void processProxyMessage(boolean messageIsRequest,
IInterceptedProxyMessage message) {
// TODO here
}
}
public interface IRequestInfo
此接口被用于獲取一個 HTTP 請求的詳細信息。擴展插件可以通過調用 IExtensionHelpers.analyzeRequest() 獲得一個 IRequestInfo 對象。
此接口提供了以下方法:
#!java
// 此方法用于獲取 HTTP body 在請求消息中的起始偏移量
int getBodyOffset()
// 此方法用于獲取請求消息的 HTTP 類型
byte getContentType()
// 此方法用于獲取請求中包含的 HTTP 頭
java.util.List<java.lang.String> getHeaders()
// 此方法用于獲取請求的 HTTP 方法
java.lang.String getMethod()
// 此方法用于獲取請求中包含的參數
java.util.List<IParameter> getParameters()
// 此方法用于獲取請求中的 URL
java.net.URL getUrl()
Demo code:
#!java
package burp;
import java.io.PrintWriter;
public class BurpExtender implements IBurpExtender, IHttpListener{
public PrintWriter stdout;
public IExtensionHelpers helpers;
@Override
public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks){
this.stdout = new PrintWriter(callbacks.getStdout(), true);
this.helpers = callbacks.getHelpers();
callbacks.setExtensionName("Her0in");
callbacks.registerHttpListener(this);
}
@Override
public void processHttpMessage(int toolFlag, boolean messageIsRequest,
IHttpRequestResponse messageInfo) {
// 打印出請求的 Url 和 響應碼
if(messageIsRequest){
stdout.println(helpers.bytesToString(messageInfo.getRequest()));
}
else{
IResponseInfo responseInfo = helpers.analyzeResponse(messageInfo.getResponse());
short statusCode = responseInfo.getStatusCode();
stdout.printf("響應碼 => %d\r\n", statusCode);
}
}
}
加載上述代碼生成的插件后,執行效果如下圖所示:
public interface IResponseInfo
此接口被用于獲取一個 HTTP 請求的詳細信息。擴展插件可以通過調用 IExtensionHelpers. analyzeResponse() 獲得一個 IResponseInfo 對象。
#!java
// 此方法用于獲取 HTTP body 在響應消息中的起始偏移量
int getBodyOffset()
// 此方法用于獲取響應消息中設置的 HTTP Cookie
java.util.List<ICookie> getCookies()
// 此方法用于獲取包含在響應消息中的 HTTP 頭
java.util.List<java.lang.String> getHeaders()
// 此方法用于獲取根據 HTTP 響應判斷出的 MIME 類型
java.lang.String getInferredMimeType()
// 此方法用于獲取 HTTP 響應頭中指示的 MIME 類型
java.lang.String getStatedMimeType()
// 此方法用于獲取 HTTP 狀態碼
short getStatusCode()
Demo code:
#!java
package burp;
import java.io.PrintWriter;
public class BurpExtender implements IBurpExtender, IHttpListener{
public PrintWriter stdout;
public IExtensionHelpers helpers;
@Override
public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks){
this.stdout = new PrintWriter(callbacks.getStdout(), true);
this.helpers = callbacks.getHelpers();
callbacks.setExtensionName("Her0in");
callbacks.registerHttpListener(this);
}
@Override
public void processHttpMessage(int toolFlag, boolean messageIsRequest,
IHttpRequestResponse messageInfo) {
// 打印出請求的 Url 和 響應碼
if(messageIsRequest){
stdout.println(helpers.bytesToString(messageInfo.getRequest()));
}
else{
IResponseInfo responseInfo = helpers.analyzeResponse(messageInfo.getResponse());
short statusCode = responseInfo.getStatusCode();
stdout.printf("響應碼 => %d\r\n", statusCode);
}
}
}
public interface IScanIssue
此接口用于獲取 Scanner 工具掃描到的問題的細節。擴展可以通過注冊一個 IScannerListener 或者是 通過調用 IBurpExtenderCallbacks.getScanIssues() 獲取掃描問題的細節。擴展同樣可以通過注冊IScannerCheck接口或者是調用IBurpExtenderCallbacks.addScanIssue()方法來自定義掃描問題,此時擴展需要提供它對此接口的實現。
此接口提供了以下方法:
#!java
// 此方法返回掃描問題的信任等級
java.lang.String getConfidence()
// 此方法返回生成掃描問題所對應的 HTTP 消息
IHttpRequestResponse[] getHttpMessages()
// 此方法返回生成掃描問題所對應的 HTTP 服務信息
IHttpService getHttpService()
// 此方法返回指定掃描問題類型的背景描述信息
java.lang.String getIssueBackground()
// 此方法返回指定的掃描問題的詳細信息
java.lang.String getIssueDetail()
// 此方法返回掃描問題類型的名稱
java.lang.String getIssueName()
// 此方法返回掃描問題類型的數字標志符
int getIssueType()
// 此方法返回指定掃描問題的解決方式的背景描述信息
java.lang.String getRemediationBackground()
// 此方法返回指定掃描問題的解決方式的背景詳情
java.lang.String getRemediationDetail()
// 此方法返回掃描問題的錯誤等級
java.lang.String getSeverity()
// 此方法返回生成掃描問題對應的 URL 信息
java.net.URL getUrl()
Demo code:
請見 IScannerListener 的實例代碼。
public interface IScannerCheck
擴展可以實現此接口,之后可以通過調用IBurpExtenderCallbacks.registerScannerCheck() 注冊一個自定義的 Scanner 工具的檢查器。Burp 將會告知檢查器執行“主動掃描”或“被動掃描”,并且在確認掃描到問題時給出報告。
#!java
// 當自定義的Scanner工具的檢查器針對同一個 URL 路徑報告了多個掃描問題時,Scanner 工具會調用此方法
int consolidateDuplicateIssues(IScanIssue existingIssue, IScanIssue newIssue)
// Scanner 工具會對每一個可插入的點執行“主動掃描”
java.util.List<IScanIssue> doActiveScan(IHttpRequestResponse baseRequestResponse, IScannerInsertionPoint insertionPoint)
// Scanner 工具會對每一個可插入的點執行“被動掃描”
java.util.List<IScanIssue> doPassiveScan(IHttpRequestResponse baseRequestResponse)
Demo code:
#!java
package burp;
import java.io.PrintWriter;
import java.util.List;
public class BurpExtender implements IBurpExtender, IScannerCheck{
public PrintWriter stdout;
public IExtensionHelpers helpers;
@Override
public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks){
this.stdout = new PrintWriter(callbacks.getStdout(), true);
this.helpers = callbacks.getHelpers();
callbacks.setExtensionName("Her0in");
callbacks.registerScannerCheck(this);
}
@Override
public List<IScanIssue> doPassiveScan(
IHttpRequestResponse baseRequestResponse) {
// TODO here
return null;
}
@Override
public List<IScanIssue> doActiveScan(
IHttpRequestResponse baseRequestResponse,
IScannerInsertionPoint insertionPoint) {
// TODO here
return null;
}
@Override
public int consolidateDuplicateIssues(IScanIssue existingIssue,
IScanIssue newIssue) {
// TODO here
return 0;
}
}
public interface IScannerInsertionPoint
此接口被用于定義一個用于Scanner工具檢查器掃描的插入點。擴展可以通過注冊IScannerCheck 獲得此接口實例,或者通過注冊IScannerInsertionPointProvider 創建一個 Burp 所使用的掃描檢查器實例。
#!java
// 此方法用于使用指定的 payload 在插入點構建一個請求
byte[] buildRequest(byte[] payload)
// 此方法返回插入點的基本值
java.lang.String getBaseValue()
// 此方法返回插入點的名稱
java.lang.String getInsertionPointName()
// 此方法返回插入點的類型,插入點類型在IScannerInsertionPoint接口中定義
byte getInsertionPointType()
// 當使用指定的 payload 替換到插入點時,此方法可以決定 payload 在請求中的偏移量
int[] getPayloadOffsets(byte[] payload)
Demo code:
請見 IScannerCheck 的實例代碼。
public interface IScannerInsertionPointProvider
擴展可以實現此接口并且可以通過調用IBurpExtenderCallbacks.registerScannerInsertionPointProvider()注冊自定義掃描插入點的工廠。
此接口提供了以下方法:
#!java
// 當掃描請求為“主動掃描”時, Scanner 工具將會調用此方法,并且提供者應該提供一個自定義插入點的列表以便用于掃描
java.util.List<IScannerInsertionPoint> getInsertionPoints(IHttpRequestResponse baseRequestResponse)
public interface IScannerListener
擴展可以實現此接口,并且可以通過調用IBurpExtenderCallbacks.registerScannerListener() 注冊一個 Scanner 工具的監聽器。當 Scanner 工具掃描到新的問題時,會通知此監聽器。擴展通過注冊這樣的監聽器用于針對掃描問題自定義的分析和記錄。
此接口提供了以下方法:
#!java
// 當一個新的掃描問題被添加到 Burp 的Scanner工具的掃描結果中時,此方法將被 Burp 調用
void newScanIssue(IScanIssue issue)
Demo code:
#!java
package burp;
import java.io.PrintWriter;
public class BurpExtender implements IBurpExtender, IScannerListener{
public PrintWriter stdout;
public IExtensionHelpers helpers;
@Override
public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks){
this.stdout = new PrintWriter(callbacks.getStdout(), true);
this.helpers = callbacks.getHelpers();
callbacks.setExtensionName("Her0in");
callbacks.registerScannerListener(this);
}
@Override
public void newScanIssue(IScanIssue issue) {
// TODO Auto-generated method stub
stdout.println("掃描到新的問題 :");
stdout.println("url => " + issue.getUrl());
stdout.println("詳情 => " + issue.getIssueDetail());
}
}
加載上述代碼生成的插件后,執行效果如下圖所示:
public interface IScanQueueItem
此接口被用于獲取在 Burp 的 Scanner 工具中激活的掃描隊列里的項目詳情。擴展可以通過調用IBurpExtenderCallbacks.doActiveScan() 獲得掃描隊列項目的引用。
#!java
// 此方法可以取消掃描隊列項目中的掃描狀態
void cancel()
// 獲取掃描隊列項目生成的問題的細節
IScanIssue[] getIssues()
// 此方法返回掃描隊列項目發生錯誤時的網絡錯誤號
int getNumErrors()
// 此方法返回掃描隊列項目的攻擊插入點的數量
int getNumInsertionPoints()
// 此方法返回掃描隊列項目已經發出的請求的數量
int getNumRequests()
// 此方法返回掃描隊列項目中已經完成掃描的百分比
byte getPercentageComplete()
// 此方法返回掃描隊列項目的狀態描述
java.lang.String getStatus()
public interface IScopeChangeListener
擴展可以實現此接口并且可以通過調用IBurpExtenderCallbacks.registerScopeChangeListener()注冊一個 Target 工具下的 scope 變化監聽器。當 Burp 的 Target 工具下的 scope 發生變化時,將會通知此接口。
此接口提供了以下方法:
#!java
// 當 Burp 的 Target 工具下的 scope 發生變化時,將會調用此方法。
void scopeChanged()
Demo code:
#!java
package burp;
import java.io.PrintWriter;
public class BurpExtender implements IBurpExtender, IScopeChangeListener{
public PrintWriter stdout;
public IExtensionHelpers helpers;
@Override
public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks){
this.stdout = new PrintWriter(callbacks.getStdout(), true);
this.helpers = callbacks.getHelpers();
callbacks.setExtensionName("Her0in");
callbacks.registerScopeChangeListener(this);
}
@Override
public void scopeChanged() {
// 手動添加或右鍵菜單添加目標到 scope 列表,就會執行此方法
stdout.println("scope 有變化!");
}
}
加載上述代碼生成的插件后,執行效果如下圖所示:
public interface ISessionHandlingAction
擴展可以實現此方法并且可以通過調用IBurpExtenderCallbacks.registerSessionHandlingAction() 注冊一個自定義的會話操作動作。每一個已注冊的會話操作動作在會話操作規則的UI中都是可用的,并且用戶可以選擇其中一個作為會話操作行為的規則。用戶可以選擇直接調用操作,也可以按照宏定義調用操作。
此接口調用了如下方法:
#!java
// 此方法由 Burp 調用獲取會話操作行為的名稱
java.lang.String getActionName()
// 當會話操作行為被執行時會調用此方法
void performAction(IHttpRequestResponse currentRequest, IHttpRequestResponse[] macroItems)
public interface ITab
此接口用于自定義的標簽頁,調用IBurpExtenderCallbacks.addSuiteTab()方法可以在 Burp 的 UI 中顯示自定義的標簽頁。
#!java
// 此方法用于獲取自定義標簽的標題文本
java.lang.String getTabCaption()
// Burp 調用此方法獲取自定義標簽頁顯示的組件
java.awt.Component getUiComponent()
Demo code:
#!java
package burp;
import java.awt.Component;
import java.io.PrintWriter;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class BurpExtender implements IBurpExtender, ITab{
public PrintWriter stdout;
public IExtensionHelpers helpers;
private JPanel jPanel1;
private JButton jButton1;
@Override
public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks){
this.stdout = new PrintWriter(callbacks.getStdout(), true);
this.helpers = callbacks.getHelpers();
callbacks.setExtensionName("Her0in");
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
//創建一個 JPanel
jPanel1 = new JPanel();
jButton1 = new JButton("點我");
// 將按鈕添加到面板中
jPanel1.add(jButton1);
//自定義的 UI 組件
callbacks.customizeUiComponent(jPanel1);
//將自定義的標簽頁添加到Burp UI 中
callbacks.addSuiteTab(BurpExtender.this);
}
});
}
@Override
public String getTabCaption() {
// 返回自定義標簽頁的標題
return "Her0in";
}
@Override
public Component getUiComponent() {
// 返回自定義標簽頁中的面板的組件對象
return jPanel1;
}
}
加載上述代碼生成的插件后,執行效果如下圖所示:
public interface ITempFile
此接口用于操作調用IBurpExtenderCallbacks.saveToTempFile()創建的臨時文件。
#!java
// 刪除臨時文件,此方法已過時
void delete()
// 此方法用于獲取臨時文件內容的緩沖區
byte[] getBuffer()
public interface ITextEditor
此接口用于擴展 Burp 的 原始文本編輯器,擴展通過調用IBurpExtenderCallbacks.createTextEditor() 獲得一個此接口的實例。
#!java
// 此方法返回用于擴展添加自定義的編輯器的 UI 組件
java.awt.Component getComponent()
// 此方法用于獲取當前的已選擇的文本
byte[] getSelectedText()
// 此方法用于獲取用戶在已顯示的文本中選擇的邊界
int[] getSelectionBounds()
// 此方法用于獲取當前已顯示的文本
byte[] getText()
// 此方法用于指示用戶是否對編輯器的內容做了修改
boolean isTextModified()
// 此方法用于決定當前的編輯器是否可編輯
void setEditable(boolean editable)
// 此方法用于更新編輯器下邊的搜索框的搜索表達式
void setSearchExpression(java.lang.String expression)
// 此方法用于更新編輯器中當前已顯示的文本
void setText(byte[] text)
Demo code:
請見 IMessageEditorTabFactory 的實例代碼。