// FindFindRegexpMatch finds the first match of r in the process memory. This function works as FindFindBytesSequence // but instead of searching for a literal bytes sequence it uses a regexp. It tries to match the regexp in the memory // as is, not interpreting it as any charset in particular. func FindRegexpMatch(p process.Process, address uintptr, r *regexp.Regexp) (found bool, foundAddress uintptr, harderror error, softerrors []error) { const buffer_size = uint(4096) foundAddress = uintptr(0) found = false harderror, softerrors = memaccess.SlidingWalkMemory(p, address, buffer_size, func(address uintptr, buf []byte) (keepSearching bool) { loc := r.FindIndex(buf) if loc == nil { return true } foundAddress = address + uintptr(loc[0]) found = true return false }) return }
// FindByFindBytesSequence finds for the first occurrence of needle in the Process starting at a given address (in the // process address space). If the needle is found the first argument will be true and the second one will contain it's // address. func FindBytesSequence(p process.Process, address uintptr, needle []byte) (found bool, foundAddress uintptr, harderror error, softerrors []error) { const min_buffer_size = uint(4096) buffer_size := min_buffer_size if uint(len(needle)) > buffer_size { buffer_size = uint(len(needle)) } foundAddress = uintptr(0) found = false harderror, softerrors = memaccess.SlidingWalkMemory(p, address, buffer_size, func(address uintptr, buf []byte) (keepSearching bool) { i := bytes.Index(buf, needle) if i == -1 { return true } foundAddress = address + uintptr(i) found = true return false }) return }
func (r Runner) walkProcMemory(proc process.Process, procname string) (err error) { // find longest byte string to search for, which determines the buffer size bufsize := uint(4096) // find lowest offset, which determines start address offset := ^uintptr(0) >> 1 // verify that at least one search is interested in inspecting the memory // of this process shouldWalkMemory := false // if at least one search wants to log failures, do so, otherwise omit them logFailures := false for label, search := range r.Parameters.Searches { // if the search is not active or the search as no content or by check to run, skip it if !search.isactive || (search.checkmask&checkContent == 0 && search.checkmask&checkByte == 0) { search.deactivate() r.Parameters.Searches[label] = search continue } shouldWalkMemory = true // find the largest bufsize needed for _, c := range search.checks { if c.code&checkByte != 0 { if uint(len(c.bytes)) > (bufsize / 2) { bufsize = 2 * uint(len(c.bytes)) // pad to always have an even bufsize if bufsize%2 != 0 { bufsize++ } } } } // find the smallest offset needed if uintptr(search.Options.Offset) < offset { offset = uintptr(search.Options.Offset) } if search.Options.LogFailures { logFailures = true } } if !shouldWalkMemory { if debug { fmt.Println("walkProcMemory: no check needs to read the memory of process", proc.Pid(), procname) } return } // keep track of the number of bytes read to exit when maxlength is reached var readBytes float64 walkfn := func(curStartAddr uintptr, buf []byte) (keepSearching bool) { if readBytes == 0 { readBytes += float64(len(buf)) } else { readBytes += float64(len(buf) / 2) } if debug { fmt.Println("walkProcMemory: reading", bufsize, "bytes starting at addr", curStartAddr, "; read", readBytes, "bytes so far") } for label, search := range r.Parameters.Searches { matchedall := true if !search.isactive { continue } // if the search is meant to stop at a given address, and we're passed // that point then deactivate the search now if readBytes >= search.Options.MaxLength { search.deactivate() goto skip } keepSearching = true for i, c := range search.checks { switch c.code { case checkContent: if c.regex.FindIndex(buf) == nil { // not found matchedall = false continue } c.storeMatch(proc) search.checks[i] = c case checkByte: if bytes.Index(buf, c.bytes) < 0 { // not found matchedall = false continue } c.storeMatch(proc) search.checks[i] = c } } // if all the checks have matched on this search, deactivate it if matchedall { search.deactivate() } skip: r.Parameters.Searches[label] = search } if debug && !keepSearching { fmt.Println("walkProcMemory: stopping the memory search for", proc.Pid(), procname) } return } if debug { fmt.Println("walkProcMemory: reading memory of", proc.Pid(), procname) } err, serr := memaccess.SlidingWalkMemory(proc, offset, bufsize, walkfn) if err != nil { return err } if logFailures { for _, err = range serr { stats.Failures = append(stats.Failures, err.Error()) if debug { fmt.Printf("walkProcMemory: soft error -> %v\n", err) } } } stats.MemoryRead += readBytes return }