Use cmdRaw and cmdRawAt in Cutter.cpp

This commit is contained in:
itayc0hen 2020-03-21 15:25:50 +02:00 committed by Itay Cohen
parent 281e75389f
commit 5d02449094
2 changed files with 85 additions and 80 deletions

View File

@ -391,7 +391,6 @@ bool CutterCore::asyncCmd(const char *str, QSharedPointer<R2Task> &task)
return true;
}
// TODO: Refactor cmdRaw based on this implementation and use it inside cmdRawAt
QString CutterCore::cmdRawAt(const char *cmd, RVA address)
{
QString res;
@ -411,9 +410,8 @@ QString CutterCore::cmdRaw(const char *cmd)
r_cons_push ();
// r_cmd_call does not return the output of the command
bool success = r_cmd_call(core->rcmd, cmd);
r_cmd_call(core->rcmd, cmd);
qInfo() << "---" << success << "----\n";
// we grab the output straight from r_cons
res = r_cons_get_buffer();
@ -618,7 +616,7 @@ void CutterCore::renameFunction(const QString &oldName, const QString &newName)
void CutterCore::delFunction(RVA addr)
{
cmd("af- " + RAddressString(addr));
cmdRaw("af- " + RAddressString(addr));
emit functionsChanged();
}
@ -630,7 +628,7 @@ void CutterCore::renameFlag(QString old_name, QString new_name)
void CutterCore::delFlag(RVA addr)
{
cmd("f-@" + RAddressString(addr));
cmdRawAt("f-", addr);
emit flagsChanged();
}
@ -652,37 +650,37 @@ QString CutterCore::getInstructionOpcode(RVA addr)
void CutterCore::editInstruction(RVA addr, const QString &inst)
{
cmd("\"wa " + inst + "\" @ " + RAddressString(addr));
cmdRawAt(QString("wa %1").arg(inst), addr);
emit instructionChanged(addr);
}
void CutterCore::nopInstruction(RVA addr)
{
cmd("wao nop @ " + RAddressString(addr));
cmdRawAt("wao nop", addr);
emit instructionChanged(addr);
}
void CutterCore::jmpReverse(RVA addr)
{
cmd("wao recj @ " + RAddressString(addr));
cmdRawAt("wao recj", addr);
emit instructionChanged(addr);
}
void CutterCore::editBytes(RVA addr, const QString &bytes)
{
cmd("wx " + bytes + " @ " + RAddressString(addr));
cmdRawAt(QString("wx %1").arg(bytes), addr);
emit instructionChanged(addr);
}
void CutterCore::editBytesEndian(RVA addr, const QString &bytes)
{
cmd("wv " + bytes + " @ " + RAddressString(addr));
cmdRawAt(QString("wv %1").arg(bytes), addr);
emit stackChanged();
}
void CutterCore::setToCode(RVA addr)
{
cmd("Cd- @ " + RAddressString(addr));
cmdRawAt("Cd-", addr);
emit instructionChanged(addr);
}
@ -699,17 +697,17 @@ void CutterCore::setAsString(RVA addr, int size, StringTypeFormats type)
{
case StringTypeFormats::None:
{
command = "Cs ";
command = "Cs";
break;
}
case StringTypeFormats::ASCII_LATIN1:
{
command = "Csa ";
command = "Csa";
break;
}
case StringTypeFormats::UTF8:
{
command = "Cs8 ";
command = "Cs8";
break;
}
default:
@ -717,26 +715,20 @@ void CutterCore::setAsString(RVA addr, int size, StringTypeFormats type)
}
seekAndShow(addr);
QString arg;
if(size > 0) {
arg = QString::asprintf("%d @ %lld", size, addr);
} else {
arg = QString::asprintf("@ %lld", addr);
}
cmd(command + arg);
cmdRawAt(QString("%1 %2").arg(command).arg(size), addr);
emit instructionChanged(addr);
}
void CutterCore::removeString(RVA addr)
{
cmd("Cs- @ " + RAddressString(addr));
cmdRawAt("Cs-", addr);
emit instructionChanged(addr);
}
QString CutterCore::getString(RVA addr)
{
return cmd("ps @ " + RAddressString(addr));
return cmdRawAt("ps", addr);
}
void CutterCore::setToData(RVA addr, int size, int repeat)
@ -744,27 +736,27 @@ void CutterCore::setToData(RVA addr, int size, int repeat)
if (size <= 0 || repeat <= 0) {
return;
}
cmd("Cd- @ " + RAddressString(addr));
cmd(QString::asprintf("Cd %d %d @ %lld", size, repeat, addr));
cmdRawAt("Cd-", addr);
cmdRawAt(QString("Cd %1 %2").arg(size).arg(repeat), addr);
emit instructionChanged(addr);
}
int CutterCore::sizeofDataMeta(RVA addr)
{
bool ok;
int size = cmd("Cd. @ " + RAddressString(addr)).toInt(&ok);
int size = cmdRawAt("Cd.", addr).toInt(&ok);
return (ok ? size : 0);
}
void CutterCore::setComment(RVA addr, const QString &cmt)
{
cmd("CCu base64:" + cmt.toLocal8Bit().toBase64() + " @ " + QString::number(addr));
cmdRawAt(QString("CCu base64:%1").arg(QString(cmt.toLocal8Bit().toBase64())), addr);
emit commentsChanged();
}
void CutterCore::delComment(RVA addr)
{
cmd("CC- @ " + QString::number(addr));
cmdRawAt("CC-", addr);
emit commentsChanged();
}
@ -774,7 +766,7 @@ void CutterCore::setImmediateBase(const QString &r2BaseName, RVA offset)
offset = getOffset();
}
this->cmd("ahi " + r2BaseName + " @ " + QString::number(offset));
this->cmdRawAt(QString("ahi %1").arg(r2BaseName), offset);
emit instructionChanged(offset);
}
@ -784,7 +776,7 @@ void CutterCore::setCurrentBits(int bits, RVA offset)
offset = getOffset();
}
this->cmd("ahb " + QString::number(bits) + " @ " + QString::number(offset));
this->cmdRawAt(QString("ahb %1").arg(bits), offset);
emit instructionChanged(offset);
}
@ -794,7 +786,7 @@ void CutterCore::applyStructureOffset(const QString &structureOffset, RVA offset
offset = getOffset();
}
this->cmdRawAt("aht " + structureOffset, QString::number(offset));
this->cmdRawAt("aht " + structureOffset, offset);
emit instructionChanged(offset);
}
@ -816,6 +808,8 @@ void CutterCore::seek(ut64 offset)
if (offset == RVA_INVALID) {
return;
}
// use cmd and not cmdRaw to make sure seekChanged is emitted
cmd(QString("s %1").arg(offset));
// cmd already does emit seekChanged(core_->offset);
}
@ -844,11 +838,13 @@ void CutterCore::seek(QString thing)
void CutterCore::seekPrev()
{
// Use cmd because cmdRaw does not work with seek history
cmd("s-");
}
void CutterCore::seekNext()
{
// Use cmd because cmdRaw does not work with seek history
cmd("s+");
}
@ -861,8 +857,7 @@ RVA CutterCore::prevOpAddr(RVA startAddr, int count)
{
CORE_LOCK();
bool ok;
RVA offset = cmd("/O " + QString::number(count) + " @ " + QString::number(startAddr)).toULongLong(
&ok, 16);
RVA offset = cmdRawAt(QString("/O %1").arg(count), startAddr).toULongLong(&ok, 16);
return ok ? offset : startAddr - count;
}
@ -1045,7 +1040,7 @@ QString CutterCore::disassemble(const QByteArray &data)
QString CutterCore::disassembleSingleInstruction(RVA addr)
{
return cmd("pi 1@" + QString::number(addr)).simplified();
return cmdRawAt("pi 1", addr).simplified();
}
RAnalFunction *CutterCore::functionIn(ut64 addr)
@ -1106,7 +1101,8 @@ RVA CutterCore::getLastFunctionInstruction(RVA addr)
QString CutterCore::cmdFunctionAt(QString addr)
{
QString ret;
ret = cmd(QString("fd @ ") + addr + "~[0]");
// Use cmd because cmdRaw would not work with grep
ret = cmd(QString("fd @ %1~[0]").arg(addr));
return ret.trimmed();
}
@ -1117,6 +1113,7 @@ QString CutterCore::cmdFunctionAt(RVA addr)
void CutterCore::cmdEsil(const char *command)
{
// use cmd and not cmdRaw because of unexpected commands
QString res = cmd(command);
if (res.contains(QStringLiteral("[ESIL] Stopped execution in an invalid instruction"))) {
msgBox.showMessage("Stopped when attempted to run an invalid instruction. You can disable this in Preferences");
@ -1125,7 +1122,7 @@ void CutterCore::cmdEsil(const char *command)
QString CutterCore::createFunctionAt(RVA addr)
{
QString ret = cmd("af " + RAddressString(addr));
QString ret = cmdRaw(QString("af %1").arg(addr));
emit functionsChanged();
return ret;
}
@ -1134,8 +1131,7 @@ QString CutterCore::createFunctionAt(RVA addr, QString name)
{
static const QRegularExpression regExp("[^a-zA-Z0-9_]");
name.remove(regExp);
QString command = "af " + name + " @ " + RAddressString(addr);
QString ret = cmd(command);
QString ret = cmdRawAt(QString("af %1").arg(name), addr);
emit functionsChanged();
return ret;
}
@ -1288,7 +1284,7 @@ QList<QJsonObject> CutterCore::getStack(int size, int depth)
CORE_LOCK();
bool ret;
RVA addr = cmd("dr SP").toULongLong(&ret, 16);
RVA addr = cmdRaw("dr SP").toULongLong(&ret, 16);
if (!ret) {
return stack;
}
@ -1487,13 +1483,15 @@ QJsonObject CutterCore::getRegisterJson()
QString CutterCore::getRegisterName(QString registerRole)
{
return cmd("drn " + registerRole).trimmed();
return cmdRaw("drn " + registerRole).trimmed();
}
RVA CutterCore::getProgramCounterValue()
{
bool ok;
if (currentlyDebugging) {
// Use cmd because cmdRaw would not work with inner command backticked
// TODO: Risky command due to changes in API, search for something safer
RVA addr = cmd("dr?`drn PC`").toULongLong(&ok, 16);
if (ok) {
return addr;
@ -1504,7 +1502,7 @@ RVA CutterCore::getProgramCounterValue()
void CutterCore::setRegister(QString regName, QString regValue)
{
cmd("dr " + regName + "=" + regValue);
cmdRaw(QString("dr %1=%2").arg(regName).arg(regValue));
emit registersChanged();
emit refreshCodeViews();
}
@ -1659,6 +1657,7 @@ void CutterCore::attachRemote(const QString &uri)
connected = true;
}
}
// Use cmd because cmdRaw would not with inner command backticked
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
seekAndShow(programCounterValue);
if (!connected) {
@ -1750,6 +1749,7 @@ void CutterCore::stopDebug()
cmdEsil("aeim-; aei-; wcr; .ar-");
currentlyEmulating = false;
} else if (currentlyAttachedToPID != -1) {
// Use cmd because cmdRaw would not work with command concatenation
cmd(QString("dp- %1; o %2; .ar-").arg(
QString::number(currentlyAttachedToPID), currentlyOpenFile));
currentlyAttachedToPID = -1;
@ -1764,6 +1764,7 @@ void CutterCore::stopDebug()
ptraceFiles += "o-" + QString::number(openFile["fd"].toInt()) + ";";
}
}
// Use cmd because cmdRaw would not work with command concatenation
cmd("doc" + ptraceFiles);
}
@ -1778,6 +1779,7 @@ void CutterCore::stopDebug()
void CutterCore::syncAndSeekProgramCounter()
{
// Use cmd because cmdRaw would not work with inner command backticked
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
seekAndShow(programCounterValue);
emit registersChanged();
@ -1991,7 +1993,7 @@ void CutterCore::setDebugPlugin(QString plugin)
void CutterCore::toggleBreakpoint(RVA addr)
{
cmd("dbs " + RAddressString(addr));
cmdRaw(QString("dbs %1").arg(addr));
emit instructionChanged(addr);
emit breakpointsChanged();
}
@ -2080,27 +2082,27 @@ void CutterCore::updateBreakpoint(int index, const BreakpointDescription &config
void CutterCore::delBreakpoint(RVA addr)
{
cmd("db- " + RAddressString(addr));
cmdRaw("db- " + RAddressString(addr));
emit instructionChanged(addr);
emit breakpointsChanged();
}
void CutterCore::delAllBreakpoints()
{
cmd("db-*");
cmdRaw("db-*");
emit refreshCodeViews();
}
void CutterCore::enableBreakpoint(RVA addr)
{
cmd("dbe " + RAddressString(addr));
cmdRaw("dbe " + RAddressString(addr));
emit instructionChanged(addr);
emit breakpointsChanged();
}
void CutterCore::disableBreakpoint(RVA addr)
{
cmd("dbd " + RAddressString(addr));
cmdRaw("dbd " + RAddressString(addr));
emit instructionChanged(addr);
emit breakpointsChanged();
}
@ -2108,9 +2110,9 @@ void CutterCore::disableBreakpoint(RVA addr)
void CutterCore::setBreakpointTrace(int index, bool enabled)
{
if (enabled) {
cmd(QString("dbite %1").arg(index));
cmdRaw(QString("dbite %1").arg(index));
} else {
cmd(QString("dbitd %1").arg(index));
cmdRaw(QString("dbitd %1").arg(index));
}
}
@ -2246,21 +2248,24 @@ QList<MemoryMapDescription> CutterCore::getMemoryMap()
QStringList CutterCore::getStats()
{
QStringList stats;
cmd("fs functions");
cmdRaw("fs functions");
// The cmd coomand is frequently used in this function because
// cmdRaw would not work with grep
stats << cmd("f~?").trimmed();
QString imps = cmd("ii~?").trimmed();
stats << imps;
cmd("fs symbols");
cmdRaw("fs symbols");
stats << cmd("f~?").trimmed();
cmd("fs strings");
cmdRaw("fs strings");
stats << cmd("f~?").trimmed();
cmd("fs relocs");
cmdRaw("fs relocs");
stats << cmd("f~?").trimmed();
cmd("fs sections");
cmdRaw("fs sections");
stats << cmd("f~?").trimmed();
cmd("fs *");
cmdRaw("fs *");
stats << cmd("f~?").trimmed();
return stats;
@ -2722,9 +2727,9 @@ QList<FlagDescription> CutterCore::getAllFlags(QString flagspace)
QList<FlagDescription> ret;
if (!flagspace.isEmpty())
cmd("fs " + flagspace);
cmdRaw("fs " + flagspace);
else
cmd("fs *");
cmdRaw("fs *");
QJsonArray flagsArray = cmdj("fj").array();
for (const QJsonValue &value : flagsArray) {
@ -3276,13 +3281,13 @@ QString CutterCore::getTypeAsC(QString name, QString category)
}
QString typeName = sanitizeStringForCommand(name);
if (category == "Struct") {
output = cmd (QString("tsc %1").arg(typeName));
output = cmdRaw(QString("tsc %1").arg(typeName));
} else if (category == "Union") {
output = cmd (QString("tuc %1").arg(typeName));
output = cmdRaw(QString("tuc %1").arg(typeName));
} else if(category == "Enum") {
output = cmd (QString("tec %1").arg(typeName));
output = cmdRaw(QString("tec %1").arg(typeName));
} else if(category == "Typedef") {
output = cmd (QString("ttc %1").arg(typeName));
output = cmdRaw(QString("ttc %1").arg(typeName));
}
return output;
}
@ -3290,7 +3295,7 @@ QString CutterCore::getTypeAsC(QString name, QString category)
bool CutterCore::isAddressMapped(RVA addr)
{
// If value returned by "om. @ addr" is empty means that address is not mapped
return !Core()->cmd(QString("om. @ %1").arg(addr)).isEmpty();
return !Core()->cmdRawAt(QString("om."), addr).isEmpty();
}
QList<SearchDescription> CutterCore::getAllSearch(QString search_for, QString space)
@ -3430,7 +3435,7 @@ QList<XrefDescription> CutterCore::getXRefs(RVA addr, bool to, bool whole_functi
} else {
xref.to = xrefObject[RJsonKey::to].toVariant().toULongLong();
}
xref.to_str = Core()->cmd("fd " + QString::number(xref.to)).trimmed();
xref.to_str = Core()->cmdRaw(QString("fd %1").arg(xref.to)).trimmed();
xrefList << xref;
}
@ -3441,7 +3446,7 @@ QList<XrefDescription> CutterCore::getXRefs(RVA addr, bool to, bool whole_functi
void CutterCore::addFlag(RVA offset, QString name, RVA size)
{
name = sanitizeStringForCommand(name);
cmd(QString("f %1 %2 @ %3").arg(name).arg(size).arg(offset));
cmdRawAt(QString("f %1 %2").arg(name).arg(size), offset);
emit flagsChanged();
}
@ -3516,27 +3521,27 @@ void CutterCore::triggerFunctionRenamed(const QString &prevName, const QString &
void CutterCore::loadPDB(const QString &file)
{
cmd("idp " + sanitizeStringForCommand(file));
cmdRaw("idp " + sanitizeStringForCommand(file));
}
void CutterCore::openProject(const QString &name)
{
cmd("Po " + name);
cmdRaw("Po " + name);
QString notes = QString::fromUtf8(QByteArray::fromBase64(cmd("Pnj").toUtf8()));
QString notes = QString::fromUtf8(QByteArray::fromBase64(cmdRaw("Pnj").toUtf8()));
}
void CutterCore::saveProject(const QString &name)
{
const QString &rv = cmd("Ps " + name.trimmed()).trimmed();
const QString &rv = cmdRaw("Ps " + name.trimmed()).trimmed();
const bool ok = rv == name.trimmed();
cmd(QString("Pnj ") + notes.toUtf8().toBase64());
cmdRaw(QString("Pnj %1").arg(QString(notes.toUtf8().toBase64())));
emit projectSaved(ok, name);
}
void CutterCore::deleteProject(const QString &name)
{
cmd("Pd " + name);
cmdRaw("Pd " + name);
}
bool CutterCore::isProjectNameValid(const QString &name)
@ -3600,10 +3605,10 @@ QString CutterCore::hexdump(RVA address, int size, HexdumpFormats format)
break;
}
return cmd(QString("%1 %2 @ %3")
return cmdRawAt(QString("%1 %2")
.arg(command)
.arg(size)
.arg(address));
.arg(size),
address);
}
QByteArray CutterCore::hexStringToBytes(const QString &hex)
@ -3730,10 +3735,10 @@ void CutterCore::commitWriteCache()
{
if (!isWriteModeEnabled()) {
setWriteMode (true);
cmd("wci");
cmd("oo");
cmdRaw("wci");
cmdRaw("oo");
} else {
cmd("wci");
cmdRaw("wci");
}
}
@ -3749,10 +3754,10 @@ void CutterCore::setWriteMode(bool enabled)
// Change from read-only to write-mode
if (enabled && !writeModeState) {
cmd("oo+");
cmdRaw("oo+");
// Change from write-mode to read-only
} else {
cmd("oo");
cmdRaw("oo");
}
writeModeChanged (enabled);
}

View File

@ -76,8 +76,7 @@ public:
/**
* @brief Execute a radare2 command \a cmd. By nature, the API
* is executing raw commands, and thus ignores multiple commands and overcome command injections.
* @param cmd - a raw command to execute. If multiple commands will be passed (e.g "px 5; pd 7 && pdf") then
* only the first command will be executed.
* @param cmd - a raw command to execute. Passing multiple commands (e.g "px 5; pd 7 && pdf") will result in them treated as arguments to first command.
* @return the output of the command
*/
QString cmdRaw(const char *cmd);
@ -90,7 +89,8 @@ public:
/**
* @brief Execute a radare2 command \a cmd at \a address. The function will preform a silent seek to the address
* without triggering the seekChanged event nor adding new entries to the seek history. By nature, the
* API is executing raw commands, and thus ignores multiple commands and overcome command injections.
* API is executing a single command without going through radare2 shell, and thus ignores multiple commands
* and tries to overcome command injections.
* @param cmd - a raw command to execute. If multiple commands will be passed (e.g "px 5; pd 7 && pdf") then
* only the first command will be executed.
* @param address - an address to which Cutter will temporarily seek.