public void Should_Check_Insert() { //arrange string str1 = "Hello"; string str2 = "hello"; string resultStr = "Hehellollo"; MyStringBuilder builder = new MyStringBuilder(str1); //act var result = builder.Insert(2, str2); //assert result.ToString().ShouldBeEquivalentTo(resultStr); }
private static string cleandisasm(string[] lines) { var sb = new MyStringBuilder(); string[] instr = new string[14]; int instrc; int instrs = 0; int real_data_accesses = 0; int real_base_accesses = 0; DATA.lvars.Clear(); DATA.cache.Clear(); SortedDictionary <int, A> stuff = new SortedDictionary <int, A>(); List <BASEADDRPATCH> baseaddrpatches = new List <BASEADDRPATCH>(); sb.Append(":ENTRY").AppendLine(); sb.Append("hex").AppendLine(); int _ = 0; if (lines[_].Trim().Replace("\r", "").Length == 0) { do { _++; } while (!lines[_ - 1].StartsWith("00000000 <_main>")); } for (; _ < lines.Length; _++) { string _line = lines[_]; try { string line = _line.Trim().Replace("\r", ""); if (line.Length == 0) { continue; } if (line.EndsWith(":")) { if (comments) { sb.Append("// ").Append(line.Trim()).AppendLine(); } continue; } instrc = 0; int c = 1; while (line[c - 1] != ':') { c++; } while (line[c] == ' ' || line[c] == '\t') { c++; } do { instr[instrc++] = new string(new char[] { line[c], line[c + 1] } ); c += 3; } while (line[c] != ' ' && line [c] != '\t'); while (line[c] == ' ' || line[c] == '\t') { c++; } string comment = line.Substring(c); // >>>>>>> nextline // try to include next line if necessary // for example: // test DWORD PTR [esp+0x11223344],0x44332211 // results in: // 0: f7 84 24 44 33 22 11 test DWORD PTR [esp+0x11223344],0x44332211 // 7: 11 22 33 44 tryparsenextline: if (_ + 1 >= lines.Length) { goto skipnextline; } string nextline = lines[_ + 1].Replace("\r", "").Trim(); nextline = new Regex("^[0-9a-fA-F]+:\\s+").Replace(nextline, ""); string[] opcodes = nextline.Split(' '); foreach (string oc in opcodes) { if (oc.Length != 2) { goto skipnextline; } try { int.Parse(oc, NumberStyles.HexNumber); } catch (Exception) { goto skipnextline; } } foreach (string oc in opcodes) { instr[instrc++] = new string(new char[] { oc[0], oc[1] } ); } _++; goto tryparsenextline; skipnextline: // <<<<<<< nextline int si = 0; if (instrc == 5 && (comment.StartsWith("call") || comment.StartsWith("jmp") || comment.StartsWith("je ") || comment.StartsWith("jne ")) && instraddr(instr) > 0x40000) { si = 1; sb.Append(instr[0]).AppendLine(); instrs++; stuff.Add(instrs, new JMPCALL()); int idx = comment.IndexOf(' ') + 1; comment = comment.Substring(0, idx) + "0x" + realaddr(instr); if (correctoffsets) { patchinstr(instr, 2 * instrs + 4); } else { patchinstr(instr, instrs); } } for (int i = 1; i <= instrc - 4; i++) { int type = 0; const int TYPE_DATA = 1; const int TYPE_BASE = 2; if (instr[i] == "ee" && instr[i + 1] == "ff" && instr[i + 3] == "ee") { type = TYPE_DATA; } else if (instr[i] == "ff" && instr[i + 1] == "ee" && instr[i + 2] == "ef" && instr[i + 3] == "ee") { type = TYPE_BASE; } else { continue; } for (; si < i; si++) { sb.Append(instr[si]).Append(' '); instrs++; } switch (type) { case TYPE_DATA: //stuff.Add(instrs, new DATA(instr[i + 2], (int.Parse(instr[i + 1], NumberStyles.HexNumber) << 8) | int.Parse(instr[i], NumberStyles.HexNumber))); stuff.Add(instrs, new DATA(instr[i + 2], 0)); sb.AppendLine(); sb.Append("00 00 00 00 // DATA").Append(instr[i + 2]); real_data_accesses++; break; case TYPE_BASE: baseaddrpatches.Add(new BASEADDRPATCH(instrs)); sb.AppendLine(); sb.Append("00 00 00 00 // __BASEADDR"); real_base_accesses++; break; } instrs += 4; i += 3; si += 4; if (si < instrc) { sb.AppendLine(); } } for (; si < instrc; si++) { sb.Append(instr[si]).Append(' '); instrs++; } sb.AppendLine(); if (comments) { sb.Append("// ").Append(comment.Trim()).AppendLine(); } } catch (Exception er) { string result = er.ToString() + "\r\n" + _line; MessageBox.Show(result); return(result); } } sb.Append("end").AppendLine(); var sb2 = new MyStringBuilder(); sb2.Append("// this file is generated by asmtool").AppendLine(); sb2.Append("// https://github.com/yugecin/scmcleoscripts/tree/master/tools/asm").AppendLine(); sb2.AppendLine(); sb2.Append(":HOOKER").AppendLine(); sb2.Append("0AC6: 0@ = label @ENTRY offset").AppendLine(); sb2.AppendLine(); sb2.Append("0085: 1@ = 0@ // (int)").AppendLine(); string[] hookadrs = new string[] { "", hookaddr.Substring(6, 2), hookaddr.Substring(4, 2), hookaddr.Substring(2, 2), hookaddr.Substring(0, 2), }; sb2.Append("000E: 1@ -= 0x").Append(realaddr(hookadrs)).AppendLine(); sb2.Append("0A8C: write_memory 0x").Append(i2hs(int.Parse(hookaddr, NumberStyles.HexNumber) - 1)).Append(" size 1 value 0xE9 vp 0").AppendLine(); sb2.Append("0A8C: write_memory 0x").Append(hookaddr).Append(" size 4 value 1@ vp 0").AppendLine(); sb2.AppendLine(); sb2.Append("0AC6: 1@ = label @ENTRY offset").AppendLine(); sb2.AppendLine(); if (baseaddrpatches.Count > 0) { sb2.Append("0085: 2@ = 1@").AppendLine(); foreach (BASEADDRPATCH p in baseaddrpatches) { p.dostuff(sb2); } sb2.AppendLine(); } int offset = 0; foreach (KeyValuePair <int, A> s in stuff) { int diff = s.Key - offset; sb2.Append("000A: 1@ += ").Append(diff).AppendLine(); offset += diff; s.Value.dostuff(sb2); } sb2.AppendLine(); sb2.Append("0002: jump @NOMOREHOOKER").AppendLine().AppendLine(); sb.Insert(0, sb2.ToString()); check(check_data_accesses, real_data_accesses, "data accesses"); check(check_base_accesses, real_base_accesses, "base addr accesses"); return(sb.ToString()); }