问题
I was searching for a method to access & tamper the raw packet data sent and received by a Qt application but could not find anything. Is there any method? Or if not the application at least a method to access the packet data from a QWebView.
Is there any method to achieve any of the above two?
回答1:
I'm sorry, Sam, I cannot make it work. I've been trying everything I can imagine, but nothing goes as it would have been desired.
Let's make a short list of options and what can and cannot be done:
You can access the retrieved web page by means of obtaining the
QWebFrame
withwebView->page()->currentFrame()
and then accessing to methods likesetContents()
,setHtml()
,toHtml()
ortoPlainText()
. You can, by those functions, change dynamically the web page shown in the widget.You can access the raw response (as an array of bytes) received for each request, by means of the method
reply->readAll()
in thereplyFinished()
slot.It's possible to intercept the requests, by overriding the
QNetworkAccessManager::createRequest()
method in a network access manager of your own. There you can access the URL and the headers sent in the request and change them or cancel the request.
But... you want to access to the request and replied data for each request.
Access to the request is easy, it's already been explained by the override to the createRequest()
method in a custom QNetworkAccessManager
. But let's talk about the other part:
For what I've seen, the reply obtained from the request is read-only and IT CAN'T BE CHANGED, as it's hard-coded in the source code for
QNetworkReply
.You cannot use the
writeData()
function ofQNetworkReply
, as it is hardcoded to simply doreturn -1
!!!You can try to subclass a
QNetworkReply
of your own and return it in thecreateRequest()
method of a customQNetworkAccessManager
. You must override the functionsreadAll()
,bytesAvailable()
, andabort()
. Curiously, this method works only if the request is made to a non-HTTP destination. I think the internals ofQNetworkAccessManager
invokes different implementations of theQNetworkReply
depending of the protocol used (HTTP, FTP, ...). So this worked in a sense, but not in the way we want. This method can be used to return a predefined web page under certain conditions, for example.Considering the fact that
QNetworkAccessManager::createRequest()
must return aQNetworkReply
object, I cannot see any combination of subclassing that permits tampering in the replied byte array. It's really well protected and you must reimplement everything on those classes to be able to achieve your goal. Almost copy-paste the source classes of all theQtNetwork
part and make your own implementation.
So I think that the answer would be: "No, it seems that it cannot be done exactly as you ask; only partially".
Sorry.
回答2:
The proper method to tamper with data sent / received to and from a server in a network connection is by the means of QNetworkAccessManager
.
This class lets you send a request to a server (probably with headers) and get the response (also with headers).
You can access to the data received on the corresponding QNetworkReply
object. Also the headers of the response:
{
...
QNetworkAccessManager *qnam = new QNetworkAccessManager(this);
connect(qnam, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
QNetworkRequest request;
request.setUrl(QUrl("http://stackoverflow.com"));
request.setRawHeader("User-Agent", "Foo browser");
qnam->get(QNetworkRequest(request));
...
}
Then define the slot:
void MyWidget::replyFinished(QNetworkReply *reply)
{
QByteArray response = reply->readAll();
QString mime = reply->header(QNetworkRequest::ContentTypeHeader).toString();
...
}
Take a look at the documentation here and here.
In fact, a QWebView
has a QNetworkAccessManager
object to execute the requests and manage the replies. You can obtain that object by means of the QWebPage::networkAccessManager()
method. You can obtain the QWebPage
from a QWebView
by means of QWebView::page()
.
EDIT
To manipulate the webpage displayed by the QWebView
, you can directly set a new HTML contents by means of webView->setHtml(QString html)
.
You can also access the HTML directly by methods of the QWebFrame
class.
To obtain such object, you must do:
QWebFrame *wb = webView->page()->currentFrame();
The methods are:
void QWebFrame::setContent ( const QByteArray & data, const QString & mimeType = QString(), const QUrl & baseUrl = QUrl() )
for setting a new document in byte array.void QWebFrame::setHtml ( const QString & html, const QUrl & baseUrl = QUrl() )
does the same, but considering the content an HTML document.QString QWebFrame::toHtml () const
to get the contents as an HTML document.QString QWebFrame::toPlainText () const
the same as above, as plain text.
Look at the documentation for those functions.
EDIT 2:
Finally, if you want to access or filter the requests made by the QWebView
itself, I can see only one way: derive a class from QNetworkAccessManager
and override the methods used to make the requests and receive the answers.
Then, make an instance of that class an set it as the QNetworkAccessManager used by the QWebView.
Let me clarify with an skeleton:
class MyNAM : public QNetworkAccessManager
{
// ...
MyNAM(QObject *parent = 0) : QNetworkAccessManager(parent) { }
// ...
virtual QNetworkReply * createRequest(Operation op, const QNetworkRequest & req, QIODevice * outgoingData = 0) {
// e.g. logging of the request
// e.g. decide if the request must be made
if (some_bool_deciding) {
QNetworkAccessManager::createRequest(op, req, outgoingData);
}
else {
// or faked...
}
// etc.
}
// ...
};
In your main application, you must made:
// ...
MyNAM *nam = new MyNAM();
webview->page()->setNetworkAccessManager(nam);
// ...
From now on, all the requests will be made using that object.
This method allows a full control over the requests made by the navigator: filter and access to the request data (headers, get and post values, etc.). You could log the requests, analyze the requests and their POST/GET fields, etc.
Hope that finally helped!
回答3:
It looks like you want Wireshark http://www.wireshark.org/ or Fiddler http://www.fiddler2.com/fiddler2/, or maybe even Charles http://www.charlesproxy.com/.
These tools don't have anything to do with Qt and can be used to inspect and intercept web traffic for all sorts of programs.
回答4:
...and what about a proxy server? A good night sleep has made me think of this possibility.
You can make one following the loopback example and the torrent client example among others. So you can capture and tamper the requests AND the replies.
You can configure the proxy on the client QWebView
with webView->page()->networkAccessManager()->setProxy()
.
This involves the construction of a process that listens to the desired port (e.g. 8080) and listen to connections on the localhost.
You must implement the protocol of a proxy by:
- Analyzing the GET and POST operations,
- Receive the whole request as a binary transfer,
- Tamper with the request,
- Send the obtained request in the connection to the destination IP,
- Then you can capture the reply,
- Tamper the received reply, and
- Send the resulting response to the client webView.
Here I have no experience, but the path seems clear. It would be a lot of coding, but I think this is really a good option if not the only option.
And more importantly: it can be done!
来源:https://stackoverflow.com/questions/10775154/get-raw-packet-data-from-qt-application